.Net进阶系列(13)-异步多线程(Task和Parallel)(被替换)
一. Task开启多线程的三种形式
1. 利用TaskFactory下的StartNew方法,向StartNew传递无参数的委托,或者是Action<object>委托。
2. 利用Task.Run()开启多线程,能向其中传递无参数的委托,有参数的可以使用 Task.Run(()=>{ TestThread("ypf") })这种形式。(推荐这种方式,最简洁。)
3. 先实例化Task,然后调用Start方法进行线程的开启。 Task构造函数可以无参委托或无参委托+object类型参数。 (同样道理,无参委托赋值有参函数,可以用之前的方案解决)
1 public static void Test4() 2 { 3 //一. 各种委托的赋值 4 //1. 无参数委托(包括方法有参数,如何赋值给无参委托) 5 Action act1 = TestThread3; 6 Action act2 = () => TestThread2("测试参数1"); 7 Action act3 = () => TestThread("测试参数1", "测试参数2"); 8 9 //2. 和方法参数对应的委托 10 Action act4 = () => TestThread3(); 11 Action<string> act5 = t => TestThread2(t); 12 Action<string, string> act6 = (m, n) => TestThread(m, n); 13 14 //3. Action<object>委托 15 Action<object> act7 = t => TestThread3(); 16 Action<object> act8 = t => TestThread2(t.ToString()); 17 //多个参数的函数要用实例类的方法解决 18 19 //4. 委托赋值时不传参数,调用的时候传递 20 Action act9 = TestThread3; 21 Action<string> act10 = TestThread2; 22 Action<string, string> act11 = TestThread; 23 24 //二. TaskFactory多线程的几种情况 25 TaskFactory taskFactory = new TaskFactory(); 26 //1. 调用无参委托不需要传递参数 27 //{ 28 // taskFactory.StartNew(act1); 29 // taskFactory.StartNew(act2); 30 // taskFactory.StartNew(act3); 31 //} 32 33 //2. 调用和方法参数对应的委托,需要在调用的时候传递参数 34 //{ 35 // taskFactory.StartNew(act4); 36 // taskFactory.StartNew(act5, "测试参数1"); //不支持(StartNew没有这种重载) 37 // taskFactory.StartNew(act6, "测试参数1", "测试参数2"); //不支持(StartNew没有这种重载) 38 //} 39 40 //3. 调用Action<object>委托 41 //{ 42 // taskFactory.StartNew(act7,""); 43 // taskFactory.StartNew(act8, "测试参数1"); 44 //} 45 46 //4. 调用 委托赋值时不传参数,调用的时候传递 47 //{ 48 // taskFactory.StartNew(act9); 49 // taskFactory.StartNew(act10, "测试参数1"); //不支持(StartNew没有这种重载) 50 // taskFactory.StartNew(act11, "测试参数1", "测试参数2"); //不支持(StartNew没有这种重载) 51 //} 52 53 //三. 使用Task.Run() 多线程的几种情况 54 //1. 调用无参委托不需要传递参数 55 //{ 56 // Task.Run(act1); 57 // Task.Run(act2); 58 // Task.Run(act3); 59 // Task.Run(act4); 60 // Task.Run(act9); 61 //} 62 //除了上述五种方式,其他均不支持 63 64 //四. 利用Task实例下的Start方法开启多线程 65 //1.act1 act2 act3 act4 act9 调用无参委托不需要传递参数,均可以调用 66 //{ 67 // Task task = new Task(act9); 68 // task.Start(); 69 //} 70 //2. Action<object>委托可以使用 71 //act7和act8可以调用 72 { 73 Task task = new Task(act7, ""); 74 task.Start(); 75 } 76 { 77 Task task = new Task(act8, "测试参数1"); 78 task.Start(); 79 } 80 81 }
二. 线程等待的两种形式
1. 利用Task下的静态方法WaitAll和WaitAny,来进行线程等待。(如果是主线程执行,则卡主主线程,如果新建一个子线程执行,则卡主了子线程)
2. 利用TaskFactory下的ContinueWhenAny和ContinueWhenAll,来进行线程等待。
三. Parallel并行计算
1. 并行计算和多线程的区别:
多线程:如果要线程等待,需要单独开辟一个线程来进行线程等待,主线程在那等着。
并行计算:开启多个线程,默认就是线程等待,主线程在那等着,所以会卡主线程。
2. 并行计算的三种形式
Parallel.Invoke();
Parallel.For();
Parallel.ForEach()
1 private void button6_Click(object sender, EventArgs e) 2 { 3 Stopwatch watch = new Stopwatch(); 4 watch.Start(); 5 Console.WriteLine("----------------- 七.并行运算Parallel --------------------------"); 6 Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0} --------------------------", Thread.CurrentThread.ManagedThreadId); 7 8 //下面的测试结果发现,主线程均被卡住 9 //并行计算和多线程相比的区别: 多线程执行后,需要单独再开辟一个线程等待,然后主线程在执行。 而并行计算,开启多个线程后,不需要再开辟线程等待,直接是主线程完成后续操作 10 11 #region 写法一 12 //{ 13 // Parallel.Invoke(() => this.TestThread("bct1") 14 // , () => this.TestThread("bct2") 15 // , () => this.TestThread("bct3") 16 // , () => this.TestThread("bct4") 17 // , () => this.TestThread("bct5") 18 // ); 19 //} 20 #endregion 21 22 #region 写法二 23 //{ 24 // //前两个参数之间的差,就为并行计算线程的个数 25 // Parallel.For(5, 10, t => 26 // { 27 // //这里的t分别为:5,6,7,8,9 五个数 28 // string name = string.Format("bct{0}", t); 29 // this.TestThread(name); 30 // }); 31 //} 32 #endregion 33 34 #region 写法三 35 //{ 36 // //数组里的个数,就为并行计算线程的个数 37 // Parallel.ForEach(new int[] { 3, 5, 44, 55, 100 }, t => 38 // { 39 // //这里的t分别为:3, 5, 44, 55, 100五个数 40 // string name = string.Format("bct{0}", t); 41 // this.TestThread(name); 42 // }); 43 //} 44 #endregion 45 46 #region 写法四 47 { 48 ParallelOptions po = new ParallelOptions() 49 { 50 MaxDegreeOfParallelism = 5 //表示最大线程数为5,后面即使配置超过5,也无效 51 }; 52 Parallel.For(6, 15, po, (t, state) => 53 { 54 string name = string.Format("bct{0}", t); 55 this.TestThread(name); 56 //state.Break(); //退出单次循环(没看到实际作用) 57 // state.Stop(); //退出全部循环(没看到实际作用) 58 //return; 59 }); 60 } 61 #endregion 62 63 watch.Stop(); 64 Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0} 总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds); 65 66 }