如何建立论坛网站,甘肃企业建站系统费用,视频网站开发需要什么插件,的网页设计培训班一. FrameWork 4.0之前的线程世界 在.NET FrameWork 4.0之前#xff0c;如果我们使用线程。一般有以下几种方式#xff1a; 使用System.Threading.Thread 类#xff0c;调用实例方法Start()开启一个新线程#xff0c;调用Abort()方法来提前终止线程。使用System.Th…一. FrameWork 4.0之前的线程世界 在.NET FrameWork 4.0之前如果我们使用线程。一般有以下几种方式 使用System.Threading.Thread 类调用实例方法Start()开启一个新线程调用Abort()方法来提前终止线程。使用System.Threading.ThreadPool类调用静态方法QueueUserWorkItem()将方法放入线程池队列线程池来控制调用。使用BeginInvoke,EndInvoke,BeginRead,EnRead,BeginWrite,EndWrite等一系列的异步方法。使用System.ComponentModel.BackgroundWorker控件调用实例方法RunWorkerAsync()开启一个新线程。 二. .Net 传统异步编程概述 异步编程模型 (APM)在该模型中异步操作由一对 Begin/End 方法如 FileStream.BeginRead 和 Stream.EndRead表示。基于事件的异步模式 (EAP)在该模式中异步操作由名为“操作名称Async”和“操作名称Completed”的方法/事件对例如 WebClient.DownloadStringAsync 和 WebClient.DownloadStringCompleted表示。 EAP 是在 .NET Framework 2.0 版中引入的,在silverlight或者wpf变成中经常用到。三. Task 的优点以及功能 在任务启动后可以随时以任务延续的形式注册回调。通过使用 ContinueWhenAll 和 ContinueWhenAny 方法或者 WaitAll 方法或 WaitAny 方法协调多个为了响应 Begin_ 方法而执行的操作。在同一 Task 对象中封装异步 I/O 绑定和计算绑定操作。监视 Task 对象的状态。使用 TaskCompletionSource 将操作的状态封送到 Task 对象。 众所周知async方法只可以返回voidTask和TaskT。 对于返回void的async方法它并不是awaitable所以其他方法不能用await方法来调用它而返回Task的async方法则可以。 那么当async方法返回Task后接着await那被await的Task是一个什么概念是async方法中第一个被await的Task不它代表目标async方法的全部执行其中包括被await分割的连接Task但是不包括非await造成的多线程执行。 如下代码在doo是一个返回Task的async方法然后在另一个方法test中await调用doo然后在Main方法中调用test由于Main方法不允许加async所以需要另外加一个async方法来使用await static void Main(string[] args) { test(); log(Main调用test后); Thread.Sleep(Timeout.Infinite); } //Main方法不允许加async所以我们用这个方法使用await static async void test() { log(test: await之前); await doo(); log(test: await之后); } //返回Task的async方法 static async Task doo() { log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 1; })); log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 2; })); log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 3; })); Thread.Sleep(1000); Console.WriteLine(doo中在Task外的Thread.Sleep执行完毕); } //输出方法显示当前线程的ManagedThreadId static void log(string msg) { Console.WriteLine({0}: {1}, Thread.CurrentThread.ManagedThreadId, msg); } 上面代码会输出 1: test: await之前 1: Main调用test后 3: Task 3: doo: Task结果1 4: Task 4: doo: Task结果2 3: Task 3: doo: Task结果3 doo中在Task外的Thread.Sleep执行完毕 3: test: await之后 前两句简单调用test方法await后的内容会被加在目标Task的后面然后test马上返回于是输出“Main调用test后”同时他们都是在主线程中执行的所以ManagedThreadId都是1。 接着后面就是另一个Task的执行当然在另一个线程也是test方法中await的目标Task。这个所谓的Task就是doo方法的全部执行。所以doo中三个顺序执行的Task通过await一个一个连接依次执行所以Task输出结果123。第一个Task的ManagedThreadId是3第二个是4第三个又是3原因是Task的内部执行使用了CLR的线程池所以线程得到了重复利用。 接着doo方法还没有完最后一个await造成doo方法后面的代码在这个await针对的Task执行后继续执行于是输出doo中Task外的Thread.Sleep执行完毕。 最后当doo彻底执行完test的await才结束所以最后一行输出testawait之后。 上面我说过被await的async方法返回的Task代表“目标async方法的全部执行其中包括被await分割的连接Task但是不包括非await造成的多线程执行”。 所以如果把返回Task的async方法也就是上例中的doo方法改成这样 //返回Task的async方法 static async Task doo() { log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 1; })); log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 2; })); log(doo: Task结果 await Task.Run(() { Thread.Sleep(1000); log(Task); return 3; })); //不使用await线程池多线程 ThreadPool.QueueUserWorkItem(_ { Thread.Sleep(1000); Console.WriteLine(ThreadPool.QueueUserWorkItem); }); //不使用awaitTask多线程 Task.Run(() { Thread.Sleep(1000); Console.WriteLine(Task.Run); }); } 我们加入了不用await的多线程执行分别使用ThreadPool和Task整个程序会输出这样的结果 1: test: await之前 1: Main调用test后 3: Task 3: doo: Task结果1 4: Task 4: doo: Task结果2 3: Task 3: doo: Task结果3 3: test: await之后 Task.Run ThreadPool.QueueUserWorkItem 不使用await的多线程完全脱离了test方法中await的Task是运行在test的await之后的。 另外Visual Studio会对Task.Run代码做如下警告idiframe_0.5044486353473234 frameborder0 scrollingno styleborder-style:none;width:47px; 提示Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the ‘await’ operator to the result of the call. 就是说如果不加await当前方法会继续执行直到结束不用管他因为我们现在就是在做在async方法中不用await的测试呵呵。 或许你会问为什么要用这样的方式去await另一个async方法返回的Task呢我们一直在讨论返回Task的async方法我认为看一个返回TaskT的async方法可以更好地解释这个问题。 下面我们把上面的代码改成相似的返回Taskint的async方法执行那么doo方法返回TaskT他把自己方法内3个awaited Task的结果统一相加最后返回结果并作为自己返回的Task的结果。然后在test方法中输出doo返回的结果。 完整代码 static void Main(string[] args) { test(); log(Main调用test后); Thread.Sleep(Timeout.Infinite); } //Main方法不允许加async所以我们用这个方法使用await static async void test() { log(test: await之前); Console.WriteLine(doo结果{0}, await doo()); log(test: await之后); } //返回Task的async方法 static async Taskint doo() { var res1 await Task.Run(() { Thread.Sleep(1000); log(awaited Task1执行); return var res2 await Task.Run(() { Thread.Sleep(1000); log(awaited Task2执行); return var res3 await Task.Run(() { Thread.Sleep(1000); log(awaited Task3执行); return //不使用await线程池多线程 ThreadPool.QueueUserWorkItem(_ { Thread.Sleep(1000); Console.WriteLine(ThreadPool.QueueUserWorkItem); }); //不使用awaitTask多线程 Task.Run(() { Thread.Sleep(1000); Console.WriteLine(Task.Run); }); return res1 res2 res3; } //输出方法显示当前线程的ManagedThreadId static void log(string msg) { Console.WriteLine({0}: {1}, Thread.CurrentThread.ManagedThreadId, msg); } 先看结果 1: test: await之前 1: Main调用test后 3: awaited Task1执行 4: awaited Task2执行 4: awaited Task3执行 doo结果6 4: test: await之后 ThreadPool.QueueUserWorkItem Task.Run 和上一个返回Task的例子一样当在test方法中await doo方法返回的Taskdoo内awaited Task都被先等了而没有awaited的线程都并没有被等这是为什么呢也就是上面留下的那个问题下面用这个返回Taskint的例子解释一下 在test中await doo返回的Task那么此时我们需要他的结果而他的结果是需要自己方法内所包含的其他awaited结果可以理解成被等的子结果。所以自己的结果需要其他的结果那么等这个结果必须需要等那些被依赖的结果也出来。所以test方法await doo方法的结果会同样等待所有doo内的await不会管其他doo内非await的多线程执行当然从技术角度讲也是不可能的因为async/await可以这样全靠的是编译器。转载于:https://www.cnblogs.com/Jeely/p/10997338.html