我这里针对现有的C#多线程技术进行一个汇总,一是复习,二是方便索引,文章部份知识点来源于网络,非本人原创。
一、并行(异步):
1.System.Threading.Tasks命名空间下的(TPL):
1.1:Parallel.Invoke --并行执行多个任务,主线程等待并行执行完毕后才开始续续运行。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | static void Main( string [] args) { Parallel.Invoke( new ParallelOptions() { MaxDegreeOfParallelism=2},Run1,Run2); Console.WriteLine( "我是主线程!" ); Console.Read(); } static void Run1() { Console.WriteLine( "我是任务一,我运行3s" ); Thread.Sleep(3000); Console.WriteLine( "任务一执先完成" ); } static void Run2() { Console.WriteLine( "我是任务二,我运行5s" ); Thread.Sleep(5000); Console.WriteLine( "任务二执先完成" ); } |
1.2:Parallel.For--循环迭代多个任务,多个任务之间存在并行情况,主线程等待循环迭代的多个任务执行完毕后才开始续续运行。
示例:
1 2 3 4 5 | Parallel.For(0, 10, (i) => { Console.WriteLine( "我是第{0}个任务,线程ID是:{1}" ,i,Thread.CurrentThread.ManagedThreadId); Thread.Sleep( new Random().Next(10) * 10 * 500); Console.WriteLine( "线程ID是:{0}执行完成" , Thread.CurrentThread.ManagedThreadId); }); |
1.3:Parallel.ForEach--循环迭代多个任务,多个任务之间存在并行情况,主线程等待循环迭代的多个任务执行完毕后才开始续续运行。注意它有多个重载方法
示例:
1 2 3 4 5 6 7 8 9 10 11 | var bag = new ConcurrentBag< int >(); Parallel.ForEach(Partitioner.Create(0, 100), i => { for ( int m = i.Item1; m < i.Item2; m++) { bag.Add(m); Console.WriteLine( "我是第{0}个任务,线程ID是:{1}" , m, Thread.CurrentThread.ManagedThreadId); } }); Console.WriteLine( "并行计算:集合有:{0}" , bag.Count); |
1.4:TAP(基于任务的异步编),使用Task类 (注意:默认任务开启后,会在新线程中执行,主线程不会等待任务而是继续下面的执行,若使用Task.WaitAll,则会等待相应的任务完成后才会执行)
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //第一种方式启动 var task1 = new Task(() => //实例化 { Run1(); }); task1.Start(); //启动 //第二种方式开启 var task2 = Task.Factory.StartNew(() => //直接创建任务并启动 { Run2(); }); //主线程等待任务执行完 Task.WaitAll(task1, task2); |
2.ParallelEnumerable类中的扩展方法(先将枚举对象使用AsParallel转换成ParallelQuery类型,然后就可以使用ParallelQuery在ParallelEnumerable类相关的扩展方法)
示例:
1 2 | var resultList = testList.AsParallel().Where(i=>i>=100).ToList(); Console.WriteLine( "resultList Count:{0}" , resultList.Count); |
3.创建新Thread--新线程启动后,主线程与创建的线程各自执行,若需要主线程等待异步线程执行完成后才执行,则应使用asyncThread.Join方法。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | static void AsyncThreadMethod() { Console.WriteLine( "我是异步执行线程,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId); } static void AsyncThreadMethod( object state) { Console.WriteLine( "我是异步执行线程,线程ID是:{0},状态:{1}" , Thread.CurrentThread.ManagedThreadId,state); } //创建线程并执行 Thread asyncThread = new Thread( new ThreadStart(AsyncThreadMethod)); asyncThread.IsBackground = true ; asyncThread.Start(); Thread asyncThread2 = new Thread( new ParameterizedThreadStart(AsyncThreadMethod)); asyncThread2.IsBackground = true ; asyncThread2.Start( "这是来自主线程的参数" ); |
4.使用ThreadPool.QueueUserWorkItem静态方法--WaitCallback回调方法要求其必需带一个object的参数
示例:
1 2 3 | ThreadPool.QueueUserWorkItem( new WaitCallback(AsyncThreadMethod)); //不带参数,则系统将state自动设为null ThreadPool.QueueUserWorkItem( new WaitCallback(AsyncThreadMethod), "这是来自主线程的参数" ); |
5.APM(异步编程模型),利用BeginInvoke与EndInvoke完成异步执行委托方法
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Func< string , string > funcDelegate = (s) => { Console.WriteLine( "我是Func委托方法!" ); return "委托方法参数:" + s; }; //1.无阻塞异步回调 var aysncResult = funcDelegate.BeginInvoke( "这是来自主线程的参数" , new AsyncCallback((result) => { //获取委托对象,调用EndInvoke方法获取运行结果 AsyncResult _result = (AsyncResult)result; var func = (Func< string , string >)_result.AsyncDelegate; string data = func.EndInvoke(_result); Console.WriteLine(data + ",附加参数:" + _result.AsyncState.ToString()); }), "其它参数" ); //2.阻塞主线程,使主线程等待执行完毕 string data2 = null ; var aysncResult2 = funcDelegate.BeginInvoke( "这是来自主线程的参数2" , null , null ); data2 = funcDelegate.EndInvoke(aysncResult2); //第一种阻塞方法 while (!aysncResult2.IsCompleted) //第二种阻塞方法 { Thread.Sleep(200); //虚拟操作 Console.WriteLine( "主线程等待..." ); } data2 = funcDelegate.EndInvoke(aysncResult2); WaitHandle[] waitHandles = new WaitHandle[]{ aysncResult2.AsyncWaitHandle }; while (WaitHandle.WaitAll(waitHandles, 5000)) //第三种阻塞方法 { Console.WriteLine( "主线程等待..." ); } |
6. EAP(基于事件的异步编程)--主要用在客户端应用程序中
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //例子一 var client = new WebClient(); client.DownloadProgressChanged += delegate ( object s, DownloadProgressChangedEventArgs e) { Console.WriteLine( "Download Percent:{0}" , e.ProgressPercentage); }; client.DownloadStringCompleted += delegate ( object s,DownloadStringCompletedEventArgs e){ Console.WriteLine( "Download Content Length:{0}" ,e.Result.Length); Console.WriteLine( "Download Completed!" ); }; client.DownloadStringAsync( new Uri( "http://www.zuowenjun.cn" )); //例子二 BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += (s, e) => { Console.WriteLine( "异步执行中。。。" ); }; worker.RunWorkerCompleted += (s, e) => { Console.WriteLine( "异步执行完成。。。" ); }; worker.RunWorkerAsync(); |
7.async和await关键字
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public Task< double > GetValueAsync( double num1, double num2) { return Task.Run(() => { for ( int i = 0; i < 1000000; i++) { num1 = num1 / num2; } return num1; }); } public async void DisplayValue() { double result = await GetValueAsync(1234.5, 1.01); //此处会开新线程处理GetValueAsync任务,然后方法马上返回 //这之后的所有代码都会被封装成委托,在GetValueAsync任务完成时调用 System.Diagnostics.Debug.WriteLine( "Value is : " + result); } //调用 DisplayValue(); //不会阻塞主线程 |
参考以下相关文章:
C#综合揭秘——细说多线程(上)
C#综合揭秘——细说多线程(下)
8天玩转并行开发系列文章
.NET基础拾遗(5)多线程开发基础