1. 程式人生 > >異步和多線程,委托異步調用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource

異步和多線程,委托異步調用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource

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