using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyThreads { /// <summary> /// C# 5.0 /// .net framework4.5 /// CLR4.0 /// 引入了async 和 await。这两个关键字可以让你更方便的写出异步代码。 /// async/await是依附于Task的异步, /// 只有async方法认为是同步的,只是返回结果类型是 /// await一定存在于async方法里面 只有async没有await的话是同步方法 /// 返回的结果是Task<T>,其中T为最终结果 /// await关键字只能放在Task前面 /// </summary> public class AwaitAsync { public static void TestAwait() { Test(); } private async static Task Test() { Console.WriteLine("当前主线程id={0}", Thread.CurrentThread.ManagedThreadId); { //NoReturnNoAwait(); } //{ //NoReturn(); //} { //Task t = NoReturnTask(); //Console.WriteLine("Main Thread Task ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId); ////t.Wait();//主线程等待Task的完成 //await t;//await后的代码会由子线程执行 } //{ //Task<long> t = SumAsync(); //Console.WriteLine("Main Thread Task ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId); //long lResult = t.Result;//访问result 主线程等待Task的完成 //t.Wait();//等价于上一行 //} //{ Task<int> t = SumFactory(); Console.WriteLine("Main Thread ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId); long lResult = t.Result;//没有await和async 普通的task t.Wait(); //} //Console.WriteLine("Test Sleep Start {0}", Thread.CurrentThread.ManagedThreadId); //Thread.Sleep(10000); //Console.WriteLine("Test Sleep End {0}", Thread.CurrentThread.ManagedThreadId); //Console.WriteLine("Main Thread ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId); Console.Read(); } /// <summary> /// 只有async没有await,会有个warn /// 跟普通方法没有区别 /// </summary> private static async void NoReturnNoAwait() { //主线程执行 Console.WriteLine("NoReturnNoAwait Sleep before Task,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); Task task = Task.Run(() =>//启动新线程完成任务 { Console.WriteLine("NoReturnNoAwait Sleep before,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(3000); Console.WriteLine("NoReturnNoAwait Sleep after,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); }); //主线程执行 Console.WriteLine("NoReturnNoAwait Sleep after Task,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); } /// <summary> /// async/await /// await 要放在task前面 /// 不推荐void返回值,使用Task来代替 /// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行 /// </summary> private static async void NoReturn() { //主线程执行 Console.WriteLine("NoReturn Sleep before await,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); TaskFactory taskFactory = new TaskFactory(); Task task = taskFactory.StartNew(() => { Console.WriteLine("NoReturn Sleep before,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(3000); Console.WriteLine("NoReturn Sleep after,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); }); await task; //子线程执行 其实是封装成委托,在task之后成为回调(编译器功能 状态机实现) Console.WriteLine("NoReturn Sleep after await,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); } /// <summary> /// 无返回值 async Task == async void /// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行 /// </summary> /// <returns></returns> private static async Task NoReturnTask() { //这里还是主线程的id Console.WriteLine("NoReturnTask Sleep before await,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); Task task = Task.Run(() => { Console.WriteLine("NoReturnTask Sleep before,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(3000); Console.WriteLine("NoReturnTask Sleep after,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); }); await task; Console.WriteLine("NoReturnTask Sleep after await,ThreadId={0}", Thread.CurrentThread.ManagedThreadId); //return new TaskFactory().StartNew(() => { }); 不能return } /// <summary> /// 带返回值的Task /// 要使用返回值就一定要等子线程计算完毕 /// </summary> /// <returns>async 就只返回long</returns> private static async Task<long> SumAsync() { Console.WriteLine("SumAsync {1} start ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, 111); long result = 0; await Task.Run(() => { for (int k = 0; k < 10; k++) { Console.WriteLine("SumAsync {1} await Task.Run ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, k); System.Threading.Thread.Sleep(1000); } for (long i = 0; i < 999999999; i++) { result += i; } }); Console.WriteLine("SumAsync {1} end ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, 111); return result; } /// <summary> /// 带返回值的Task /// 要使用返回值就一定要等子线程计算完毕 /// </summary> /// <returns>没有async Task</returns> private static Task<int> SumFactory() { Console.WriteLine("SumFactory {1} start ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, 111); TaskFactory taskFactory = new TaskFactory(); Task<int> iResult = taskFactory.StartNew<int>(() => { System.Threading.Thread.Sleep(3000); Console.WriteLine("SumFactory {1} Task.Run ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, 123); return 123; }); //Console.WriteLine("This is {0}", iResult.Result); Console.WriteLine("SumFactory {1} end ManagedThreadId={0}", Thread.CurrentThread.ManagedThreadId, 111); return iResult; } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace MyThreads { /// <summary> /// 1 作业讲解,事件回顾 /// 2 进程-线程-多线程,同步和异步 /// 3 异步使用和回调 /// 4 异步参数 /// 5 异步等待 /// 6 异步返回值 /// /// 1 多线程的特点:不卡主线程、速度快、无序性 /// 2 thread:线程等待,回调,前台线程/后台线程, /// 3 threadpool:线程池使用,设置线程池,ManualResetEvent /// 4 Task初步接触 /// /// 1 task:waitall waitany continueWhenAny continueWhenAll /// 2 并行运算Parallel /// 3 异常处理、线程取消、多线程的临时变量和lock /// 4 Await/Async /// 5 作业 /// </summary> public partial class Form1 : Form { public Form1() { Console.WriteLine("今天多线程课程================================================"); InitializeComponent(); } #region btnSync_Click /// <summary> /// 同步方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSync_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("**********************btnSync_Click Start 主线程id {0}****************************************", Thread.CurrentThread.ManagedThreadId); for (int i = 0; i < 5; i++) { string name = string.Format("btnSync_Click_{0}", i); TestThread(name); } watch.Stop(); Console.WriteLine("**********************btnSync_Click End 主线程id {0} {1}*******************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region btnAsync_Click /// <summary> /// 委托的异步调用 /// 异步多线程的三大特点: /// 1 同步方法卡界面,原因是主线程被占用;异步方法不卡界面,原因是计算交给了别的线程,主线程空闲 /// 2 同步方法慢,原因是只有一个线程计算;异步方法快,原因是多个线程同时计算,但是更消耗资源,不宜太多 /// 3 异步多线程是无序的,启动顺序不确定、执行时间不确定、结束时间不确定 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAsync_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("***********************btnAsync_Click Start 主线程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); for (int i = 0; i < 5; i++) { string name = string.Format("btnAsync_Click_{0}", i); Action act = () => this.TestThread(name); //AsyncCallback actCallback = t => Console.WriteLine("123"); //act.BeginInvoke(actCallback, null); act.BeginInvoke(null, null); //ThreadStart method = () => this.TestThread(name); //Action callback = () => Console.WriteLine("123"); //this.ThreadCallback(method, callback); } watch.Stop(); Console.WriteLine("**********************btnAsync_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region btnThread_Click /// <summary> /// Threads /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnThread_Click(object sender, EventArgs e) { 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 = () => this.TestThread(name); Thread thread = new Thread(method);//1 默认前台线程:程序退出后,计算任务会继续 thread.IsBackground = true;//2 后台线程:程序退出,计算立即结束 thread.Start(); threadList.Add(thread); //ParameterizedThreadStart method = o => this.TestThread(o.ToString()); //Thread thread = new Thread(method); //thread.Start(name); } foreach (Thread thread in threadList) { thread.Join(); } watch.Stop(); Console.WriteLine("**********************btnThread_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } /// <summary> /// 使用Thread 完成多线程回调 /// </summary> /// <param name="method">要多线程执行的任务</param> /// <param name="callback">回调执行的任务</param> private void ThreadBeginInvoke(ThreadStart method, Action callback) { ThreadStart methodAll = new ThreadStart(() => { method.Invoke(); callback.Invoke(); }); Thread thread = new Thread(methodAll); thread.Start(); } #endregion #region btnThreadPool_Click /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnThreadPool_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("***********************btnThreadPool_Click Start 主线程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); //for (int i = 0; i < 5; i++) //{ // string name = string.Format("btnThreadPool_Click_{0}", i); // WaitCallback method = t => this.TestThread(t.ToString()); // ThreadPool.QueueUserWorkItem(method, name); //} ManualResetEvent mre = new ManualResetEvent(false); WaitCallback method = t => { this.TestThread(t.ToString()); mre.Set(); }; ThreadPool.QueueUserWorkItem(method, "TestManualResetEvent"); Console.WriteLine("我们来干点别的。。。。"); Console.WriteLine("我们来干点别的。。。。"); Console.WriteLine("我们来干点别的。。。。"); Console.WriteLine("我们来干点别的。。。。"); mre.WaitOne(); //ManualResetEvent mre = new ManualResetEvent(false); //new Action(() => //{ // Thread.Sleep(5000); // Console.WriteLine("委托的异步调用"); // mre.Set();//打开 //}).BeginInvoke(null, null); //mre.WaitOne(); //Console.WriteLine("12345"); //mre.Reset();//关闭 //new Action(() => //{ // Thread.Sleep(5000); // Console.WriteLine("委托的异步调用2"); // mre.Set();//打开 //}).BeginInvoke(null, null); //mre.WaitOne(); //Console.WriteLine("23456"); //ThreadPool.SetMaxThreads(8, 8);//最小也是核数 //ThreadPool.SetMinThreads(8, 8); //int workerThreads; //int ioThreads; //ThreadPool.GetMaxThreads(out workerThreads, out ioThreads); //Console.WriteLine(String.Format("Max worker threads: {0}; Max I/O threads: {1}", workerThreads, ioThreads)); //ThreadPool.GetMinThreads(out workerThreads, out ioThreads); //Console.WriteLine(String.Format("Min worker threads: {0}; Min I/O threads: {1}", workerThreads, ioThreads)); //ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads); //Console.WriteLine(String.Format("Available worker threads: {0}; Available I/O threads: {1}", workerThreads, ioThreads)); watch.Stop(); Console.WriteLine("**********************btnThreadPool_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region btnTask_Click /// <summary> /// Task /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnTask_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("***********************btnTask_Click Start 主线程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); //new Action(() => //{ TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); for (int i = 0; i < 5; i++) { string name = string.Format("btnAsync_Click_{0}", i); //Action act = () => this.TestThread(name); //Task task = taskFactory.StartNew(act); Action<object> act = t => this.TestThread(name); Task task = taskFactory.StartNew(act, name); //task.ContinueWith(t => //{ // //t.AsyncState // Console.WriteLine("这里是ContinueWhenAny {0}", Thread.CurrentThread.ManagedThreadId); //}); taskList.Add(task); //Task task = new Task(act); //task.Start(); //Task task = Task.Run(act); } Task any = taskFactory.ContinueWhenAny(taskList.ToArray(), t => { //t.AsyncState Console.WriteLine("这里是ContinueWhenAny {0}", Thread.CurrentThread.ManagedThreadId); }); Task all = taskFactory.ContinueWhenAll(taskList.ToArray(), tList => { Console.WriteLine("这里是ContinueWhenAll {0}", Thread.CurrentThread.ManagedThreadId); }); //name="btnAsync_Click_{2}" //Task.WaitAny(task); Task.WaitAny(taskList.ToArray());//执行的线程等待某一个task的完成 Console.WriteLine("after WaitAny{0}", Thread.CurrentThread.ManagedThreadId); Task.WaitAll(taskList.ToArray());//执行的线程等待全部的task的完成 Console.WriteLine("after WaitAll{0}", Thread.CurrentThread.ManagedThreadId); //}).BeginInvoke(null, null); //Console.WriteLine("out BeginInvoke"); watch.Stop(); Console.WriteLine("**********************btnTask_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region btnParallel_Click /// <summary> /// 并行计算 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnParallel_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("***********************btnParallel_Click Start 主线程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); //Parallel.Invoke(() => this.TestThread("btnParallel_Click_0") // , () => this.TestThread("btnParallel_Click_1") // , () => this.TestThread("btnParallel_Click_2") // , () => this.TestThread("btnParallel_Click_3") // , () => this.TestThread("btnParallel_Click_4")); //等于使用4个task,然后主线程同步invoke一个委托 然后主线程waitall //Parallel.For(6, 10, t => //{ // string name = string.Format("For btnParallel_Click_{0}", t); // this.TestThread(name); //}); //Parallel.ForEach(new int[] { 5, 6, 7, 10, 8473847 }, t => //{ // string name = string.Format("ForEach btnParallel_Click_{0}", t); // this.TestThread(name); //}); ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = 5 }; Parallel.For(6, 15, parallelOptions, (t, state) => { string name = string.Format("btnParallel_Click_{0}", t); this.TestThread(name); //state.Break();//退出单次循环 //state.Stop();//退出全部的循环 //return; }); watch.Stop(); Console.WriteLine("**********************btnParallel_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region btnThreadCore_Click private int TotalCount = 0; private static List<int> IntList = new List<int>(); private static object btnThreadCore_Click_Lock = new object(); /// <summary> /// 异常处理、线程取消、多线程的临时变量和线程安全lock /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnThreadCore_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("***********************btnThreadCore_Click Start 主线程id {0}**********************************", Thread.CurrentThread.ManagedThreadId); try { TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); #region 异常处理 //多线程的委托是不允许异常的, try catch包住,写下日志 //for (int i = 0; i < 20; i++) //{ // string name = string.Format("btnThreadCore_Click{0}", i); // Action<object> act = t => // { // try // { // Thread.Sleep(2000); // if (t.ToString().Equals("btnThreadCore_Click11")) // { // throw new Exception(string.Format("{0} 执行失败", t)); // } // if (t.ToString().Equals("btnThreadCore_Click12")) // { // throw new Exception(string.Format("{0} 执行失败", t)); // } // Console.WriteLine("{0} 执行成功", t); // } // catch (Exception ex) // { // Console.WriteLine(ex.Message); // } // }; // taskList.Add(taskFactory.StartNew(act, name)); //} //Task.WaitAll(taskList.ToArray()); #endregion #region 线程取消 ////Task不能主动取消,只能通过信号量检查的方式 //CancellationTokenSource cts = new CancellationTokenSource(); //for (int i = 0; i < 40; i++) //{ // string name = string.Format("btnThreadCore_Click{0}", i); // Action<object> act = t => // { // try // { // //if (cts.IsCancellationRequested) // //{ // // Console.WriteLine("{0} 取消一个任务的执行", t); // //} // Thread.Sleep(2000); // if (t.ToString().Equals("btnThreadCore_Click11")) // { // throw new Exception(string.Format("{0} 执行失败", t)); // } // if (t.ToString().Equals("btnThreadCore_Click12")) // { // 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(ex.Message); // } // }; // taskList.Add(taskFactory.StartNew(act, name, cts.Token));//没有启动的任务 在Cancel后放弃启动 //} //Task.WaitAll(taskList.ToArray()); #endregion #region 多线程临时变量 //for (int i = 0; i < 5; i++) //{ // //int k = i; // new Action(() => // { // //Thread.Sleep(100); // Console.WriteLine(i); // //Console.WriteLine(k); // }).BeginInvoke(null, null); //} //foreach (var item in collection) //{ // //做了事件的注册 每次用的都是item //} #endregion #region 线程安全 lock for (int i = 0; i < 10000; i++) { int newI = i; taskList.Add(taskFactory.StartNew(() => { int k = 2; int w = 3; int iResult = k + w; lock (btnThreadCore_Click_Lock) { this.TotalCount += 1; IntList.Add(newI); } })); } Task.WaitAll(taskList.ToArray()); Console.WriteLine(this.TotalCount); Console.WriteLine(IntList.Count()); #endregion } catch (AggregateException aex) { foreach (var item in aex.InnerExceptions) { Console.WriteLine(item.Message); } } catch (Exception ex) { Console.WriteLine(ex.Message); } watch.Stop(); Console.WriteLine("**********************btnThreadCore_Click End 主线程id {0} {1}************************************", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); Console.WriteLine(); } #endregion #region Private Method /// <summary> /// 执行动作:耗时而已 /// </summary> private 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; } //Thread.Sleep(1000); 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); } #endregion } }