異步和多線程,委托異步調用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource
阿新 • • 發佈:2017-07-17
hang star mat 回調函數 system 占用 new t reac n)
1 進程-線程-多線程,同步和異步
2 異步使用和回調
3 異步參數
4 異步等待
5 異步返回值
5 多線程的特點:不卡主線程、速度快、無序性
7 thread:線程等待,回調,前臺線程/後臺線程,
8 threadpool:線程池使用,設置線程池,ManualResetEvent
9 Task初步接觸
10 task:waitall waitany continueWhenAny continueWhenAll
11並行運算Parallel
12 異常處理、線程取消、多線程的臨時變量和lock
13 Await/Async
Anker_張(博客園)http://www.cnblogs.com/AnkerZhang/
//簡單同步委托、方法調用 val是返回值 Func<int, string> func1 = i => { string result = i + "變返回值"; return result; }; string val= func1.Invoke(100); //委托、方法異步調用 func1.BeginInvoke(100, null, null);//開啟新的進程去執行方法 IAsyncResult asyncResult= null;//表示異步操作的狀態。 AsyncCallback callback = t => //回調函數方法處理 { Console.WriteLine(t.Equals(asyncResult));//運行起來是true Console.WriteLine(t.AsyncState);//t.AsyncState回調函數所需要傳的參數 Console.WriteLine("這裏是回調函數 {0}", Thread.CurrentThread.ManagedThreadId);//表示線程ID }; asyncResult = func1.BeginInvoke(100, callback, "我是回調函數參數");//參數1:委托所需int參數,2:穿入回調函數,3:回調函數參數,返回值是回調函數 bool b = asyncResult.IsCompleted;//指示異步操作是否已完成。 返回結果: 如果操作完成則為 true,否則為 false。 asyncResult.AsyncWaitHandle.WaitOne();//一直等待 asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待 asyncResult.AsyncWaitHandle.WaitOne(1000);//等待1000毫秒,超時就不等待了 func1.EndInvoke(asyncResult);//會一直等待回調函數執行完成
委托的異步調用
異步多線程的三大特點:
1 同步方法卡界面,原因是主線程被占用;異步方法不卡界面,原因是計算交給了別的線程,主線程空閑
2 同步方法慢,原因是只有一個線程計算;異步方法快,原因是多個線程同時計算,但是更消耗資源,不宜太多
3 異步多線程是無序的,啟動順序不確定、執行時間不確定、結束時間不確定
/// <summary> /// 執行動作:耗時而已 /// </summary> private static void TestThread(string threadName) { Console.WriteLine("TestThread Start Name={2}當前線程的id:{0},當前時間為{1},", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName); long sum = 0; for (int i = 1; i < 999999999; i++) { sum += i; } Console.WriteLine("TestThread End Name={2}當前線程的id:{0},當前時間為{1},計算結果{3}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName, sum); }
//多線程 Stopwatch watch = new Stopwatch();//用於計時器 watch.Start();//開始計時 Console.WriteLine(); Console.WriteLine("***********************btnThread_Click Start 主線程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); List<Thread> threadList = new List<Thread>(); for (int i = 0; i < 5; i++) { string name = string.Format("btnThread_Click_{0}", i); ThreadStart method = () => TestThread(name); Thread thread = new Thread(method);//1 默認前臺線程:程序退出後,計算任務會繼續 thread.IsBackground = true;//2 後臺線程:程序退出,計算立即結束 thread.Start();//啟動線程 threadList.Add(thread);//添加在集合 } foreach (Thread thread in threadList) { thread.Join();///等待每個線程執行完畢 } watch.Stop();//結束計算時間 Console.WriteLine("**********************btnThread_Click End 主線程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine();
線程池(ThreadPool)
可設置線程池線程數量,把線程留在程序中
每次可循環使用,不用再去和操作系統申請線程
//線程池 ManualResetEvent mre = new ManualResetEvent(false); for (int i = 0; i < 5; i++) { string name = string.Format("ThreadPool{0}", i); WaitCallback method = t => { Console.WriteLine("我是異步調用方法參數:{0}", t.ToString()); mre.Set(); //打開 mre.Reset();//關閉 }; ThreadPool.QueueUserWorkItem(method, name); } Console.WriteLine("我們來幹點別的。。。。"); Console.WriteLine("我們來幹點別的。。。。"); Console.WriteLine("我們來幹點別的。。。。"); Console.WriteLine("我們來幹點別的。。。。"); mre.WaitOne();//判斷線程是否全部執行完成 ThreadPool.SetMaxThreads(8, 8);//設置最大線程池數量和IO線程池運行數量 ThreadPool.SetMinThreads(8, 8); int workerThreads; int ioThreads; ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);//獲取當前線程狀況
Task
CRL4.0
引用 Task是基於線程池開發,效率提升
//Task CRL4.0引用 Task是基於線程池開發,效率提升 { TaskFactory taskFactory = new TaskFactory();//創建Task工廠 for (int i = 0; i < 5; i++) { string name = string.Format("Async_{0}", i); Action act = () => TestThread(name);//這個方法執行動作:耗時而已 Task task = taskFactory.StartNew(act);//這裏也可以 Task task =new Task(act); task.Start();//啟動Task } } //Task一下方法比較效率高推薦使用 { TaskFactory taskFactory = new TaskFactory();//創建Task工廠 List<Task> taskList = new List<Task>();//創建Task集合 Action<object> act = o => Console.WriteLine(o.ToString()); Task task = taskFactory.StartNew(act, "參數1");//創建一個新的委托Task方法 taskList.Add(task); taskList.Add( taskFactory.StartNew(s => Console.WriteLine(s.ToString()), "參數2")); Task any = taskFactory.ContinueWhenAny(taskList.ToArray(), t =>//taskList中任意任務線程執行完畢,就執行該方法(異步執行) { //t.AsyncState Console.WriteLine("這裏是ContinueWhenAny {0}", Thread.CurrentThread.ManagedThreadId);//打印線程ID }); Task all = taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>//taskList中全部任務線程執行完畢,就執行該方法(異步執行) { Console.WriteLine("這裏是ContinueWhenAll {0}", Thread.CurrentThread.ManagedThreadId); }); Task.WaitAny(taskList.ToArray());//執行的線程等待某一個task的完成 Task.WaitAll(taskList.ToArray());//執行的線程等待全部的task的完成 }
Parallel 並行計算
Parallel是基於Task開發,並行計算與Task.WaitAll執行等待結果不同的是:Task.WaitAll在執行時主線程在鎖死等在子線程執行完成
Parallel是主線程也同樣隨機分配一個子線程去執行任務,Parallel比Task少開啟一個線程
//Parallel 並行計算 Parallel.Invoke(() => TestThread("btnParallel_Click_0")//這個方法執行動作:耗時而已 , () => TestThread("btnParallel_Click_1")//這個方法執行動作:耗時而已 , () => TestThread("btnParallel_Click_2")//這個方法執行動作:耗時而已 , () => TestThread("btnParallel_Click_3")//這個方法執行動作:耗時而已 , () => TestThread("btnParallel_Click_4"));//這個方法執行動作:耗時而已 //等於使用4個task,然後主線程同步invoke一個委托 然後主線程waitall Parallel.For(6, 10, t => { string name = string.Format("For btnParallel_Click_{0}", t); TestThread(name);//這個方法執行動作:耗時而已 }); ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = 5//實例所允許的最大並行度。 }; Parallel.For(6, 15, parallelOptions, (t, state) => { string name = string.Format("btnParallel_Click_{0}", t); TestThread(name); state.Break();//退出單次循環 state.Stop();//退出全部的循環 return; });
異常處理、線程取消、多線程的臨時變量和線程安全lock
//異常處理、線程取消、多線程的臨時變量和線程安全lock CancellationTokenSource cts = new CancellationTokenSource();//線程取消專用實例 TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); for (int i = 0; i < 20; i++) { Action<object> act = t => { try { if (t.ToString().Equals("10"))//模擬當i=10拋異常 { throw new Exception(string.Format("{0} 執行失敗", t)); } if (!cts.IsCancellationRequested)//是否被取消 { Console.WriteLine("{0} 執行成功", t); } else { Console.WriteLine("{0} 被取消", t); } } catch (Exception ex) { cts.Cancel();// 傳達取消請求。 Console.WriteLine("子線程異常 {0}", ex.Message); } }; taskFactory.StartNew(act, i); Task task = taskFactory.StartNew(act, i, cts.Token);//加上 cts.Token 如果被取消集合裏面剩余的線程就不會啟動了 taskList.Add(task); } Task.WaitAll(taskList.ToArray()); ///多線程的臨時變量和線程安全lock ///每次實例新對象防止變量訪問沖突 ///如果同時訪問同一變量加上Lock ///private static object obj = new object(); ///lock (obj) ///{ /// 鎖住啦 ///}
異步和多線程,委托異步調用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource