- IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
- webResponse EndGetResponse(IAsyncResult asyncResult)
Event-based Asynchronous Pattern(EAP)模型以 MethodAsync(...) 和 CancelAsync(...) 结对出现, 由 Completed 事件设置回调函数.
WebClient 类中通过 DownloadStringAsync 方法开启一个异步任务, 并由 DownloadStringCompleted 事件供设置回调函数, 能通过 CancelAsync 方法取消异步任务.
.Net4.5 开始 Task Parallel Library(TPL) 为异步和并行编程提供新的模型, 使异步和并发操作有统一的编程入口,
该模型常定义以 Async 后缀结尾的函数名, 返回带有 awaitable 属性的 Task/Task<T > 对象, 如果你的 program target 设置为 4.5+, 可用 Task-based Asynchronous Pattern (TAP)取代以上 2 种模型.
TAP
TPL 的核心是 Task 类, Task,Task<TResult > 可以将其理解为一个包装委托 (通常就是 Action 或 Func 委托) 并执行的容器, 有了 Task 几乎不用去和 Thread 打交道, 使用者只需要关注具体业务对应的 Job,Task 背后有一个 TaskScheduler 的类来负责调度 Task 的执行, 这样 Task 对象将在默认的 TaskScheduler 调度下执行, TaskScheduler 使用线程池中的线程, 至于是新建还是使用已有线程这个对用户是完全透明的, 也可以通过重载函数的参数传入自定义的 TaskScheduler.
Task 任务状态:
状态 & amp; 枚举值 | 说明 < span style="font-size: 14px;" ztid="58" oh="17" ow="0"> |
Created = 0 | The task has been initialized but has not yet been scheduled |
WaitingForActivation = 1 | The task is waiting to be activated and scheduled internally by the .NET Framework infrastructure. |
WaitingToRun = 2 | The task has been scheduled for execution but has not yet begun executing. |
Running = 3 | The task is running but has not yet completed. |
WaitingForChildrenToComplete = 4 | The task has finished executing and is implicitly waiting for attached child tasks to complete. |
RanToCompletion = 5 | The task completed execution successfully |
Canceled = 6 | The task acknowledged cancellation by throwing an OperationCanceledException with its own CancellationToken while the token was in signaled state, or the task's CancellationToken was already signaled before the task started executing |
Faulted = 7 | The task completed due to an unhandled exception |
明确 Task 和线程的关系:
任务是架构在线程之上的, 也就是说任务最终还是要抛给线程去执行
任务跟线程不是一对一的关系, 比如开 10 个任务并不是说会开 10 个线程, 在. NET 面向任务异步编程模型中, 你只需要关注业务概念的任务, 具备底层实现会由 Task 包装完成.
Task 相比 ThreadPool 的优势:
ThreadPool 不支持线程取消, 完成, 失败通知等交互新操作
ThreadPool 不支持线程执行的先后顺序.
await/async 语法糖
在异步编程实践中, 将网络, 数据库同步访问称为 I/O-bound; 将等待 CPU 计算结果称为 CPU-bound
TAP 异步编程模型的核心是塑造异步操作的 Task,Task<T > 对象, 这是 awaitable 对象, await/async 语法糖简化了写法
对于 I/O-bound 代码, 编写一个返回 Task 或 Task<T > 的 async 方法, 之后 await 这个方法
对于 CPU-bound 代码, 使用 Task.Run 方法后台启动一个操作, 之后 await 这个操作.
魔法发生在 await 关键字, 会将控制权上交给执行 Async 方法的上层调用者.
在 C# 语言底层, 编译器将你的 await/async 代码转换为状态机, 记录了当 await 发生时控制权上交和后台工作完成时恢复执行的标记.
异步编程在实践时需要理解:
异步代码可用于 I/O -bound 和 CPU-bound 代码, 但是 2 个场景的写法是不同的
异步编程利用 Task 和 Task<T > 对象来 塑造需要在后台完成的工作
async 关键字将方法转变为异步方法, 这样可在方法体使用 await 关键词, 如果 async 方法内不包含 await 关键词, 那将不会上交控制权
当 await 动作发生时, 将会暂停 (注意是 suspend 而不是 block) 方法, 并将控制权上交给调用者(直到 awaitable 任务完成)
await 只能被用在 async 方法内部
执行操作的 "异步方式"
执行以下操作… | 替换以下方式… | 使用以下方式 |
检索后台任务的结果 | Task.Wait / Task.Result | await |
等待任何任务完成 | Task.WaitAny | await Task.WhenAny |
检索多个任务的结果 | Task.WaitAll | await Task.WhenAll |
等待一段时间 | Thread.Sleep | await Task.Delay |
下面是一个 I/O-bound 的例子:
- using System;
- using System.Threading;
- using System.Threading.Tasks;
- using System.NET.Http;
- namespace Test
- {
- class Program
- {
- static void Main(string[] args)
- {
- var asyncMethod = AccessTheWebAsync();
- Console.WriteLine("go on ......"+ Thread.CurrentThread.ManagedThreadId );
- // 等待异步线程处理完毕, 没有以下句子, await 使控制回到调用方, 主线程即终止.
- asyncMethod.Wait();
- }
- public static async Task<int> AccessTheWebAsync()
- {
- HttpClient client = new HttpClient();
- // GetStringAsync returns a Task<string>.
- // That means that when you await the task you'll get a string (urlContents).
- Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
- // You can do work here that doesn't rely on the string from GetStringAsync.
- DoIndependentWork();
- // The await operator suspends AccessTheWebAsync.
- // - AccessTheWebAsync can't continue until getStringTask is complete.
- // - Meanwhile, control returns to the caller of AccessTheWebAsync.
- // - Control resumes here when getStringTask is complete.
- // - The await operator then retrieves the string result from getStringTask.
- string urlContents = await getStringTask;
- Console.WriteLine(urlContents.Length+"......."+Thread.CurrentThread.ManagedThreadId );
- // The return statement specifies an integer result.
- // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
- return urlContents.Length;
- }
- public static void DoIndependentWork()
- {
- Console.WriteLine("work ......"+Thread.CurrentThread.ManagedThreadId);
- }
- }
- }
以上代码在 ASP.NET 或 GUI 程序可能会发生死锁, 具体参见《.NET 异步编程系列 3: 掌握 SynchronizationContext 避免 deadlock》; 控制台程序经过验证在. NET Core 和. Net Framework 上都没有 SynchronizationContext, 故不会发生死锁.
Task 对象提供了丰富的 API 帮助我们完成 基于任务的异步操作, 让我们专注业务概念的任务.
作者: Julian_酱
感谢您的认真阅读, 如有问题请大胆斧正, 如果您觉得本文对你有用, 不妨右下角点个 或加关注.
来源: https://www.cnblogs.com/mi12205599/p/10678887.html