【C# TAP 异步编程】二 、await运算符已经可等待类型Awaitable
await的作用:
1、await是一个标记,告诉编译器生成一个等待器来等待可等待类型实例的运行结果。
2、一个await对应一个等待器 ,任务的等待器类型是TaskAwaiter/TaskAwaiter<TResult>。
3、Await 就像一个一元运算符:它接受一个参数,一个可等待的"awaitable"类型的实例。它暂停对其所属的 async 方法的求值,直到其 【操作数】 表示的异步操作完成。 异步操作完成后,await
运算符将返回操作的结果(如果有)。
await task等效于task.GetAwaiter().GetResult()。task.GetAwaiter() 返回TaskAwaiter/TaskAwaiter<TResult>
4、可等待类型awaitable:Task、Task<TResult>、ValueTask、Task.Yield()、ConfiguredTaskAwaitable ConfigureAwait()、包含GetAwaiter()的鸭子类型
等待者模式
Await/Async 异步使模式使用的是等待者模式。等待者模式要求等待者公开IsCompleted属性,GetResult
方法和OnCompleted
方法(可选地带有UnsafeOnCompleted
方法,unsafe表示不使用可执行上下 回导致漏洞)。
await用法
await 类型实例TTT
该【类型实例TTT】的类型必须包含 GetAwaiter()方法,并且GetAwaiter()方法的返回值类型继承INotifyCompletion接口,实现属性public bool IsCompleted { get; },方法public void GetResult() { }。使用方法和枚举器IEnumerable、 Enumerator一样。
例如:Task类包含GetAwaiter()方法,GetAwaiter()方法的返回值TaskAwaiter类 继承INotifyCompletion接口,TaskAwaiter类实现属性IsCompleted和方法GetResult()。
//Task类型 public TaskAwaiter GetAwaiter() { return new TaskAwaiter(this); } ///TaskAwaiter类 实现了属性IsCompleted、方法GetResult()以及INotifyCompletion接口
明白原理后,自定义一个类
using System.Runtime.CompilerServices; Task t = AsynchronousProcessing(); t.Wait(); Console.ReadLine(); static async Task AsynchronousProcessing() { var sync = new CustomAwaitable(true); string result = await sync; // Completed synchronously Console.WriteLine(result); var async = new CustomAwaitable(false); result = await async; // Task is running on a thread id 3. Is thread pool thread: True Console.WriteLine(result); } /// <summary> /// 类型t /// </summary> class CustomAwaitable { private readonly bool _completeSynchronously; public CustomAwaitable(bool completeSynchronously) { _completeSynchronously = completeSynchronously; } /// <summary> /// t有一个名为GetAwaiter的可访问的实例或扩展方法 /// </summary> /// <returns>类型A</returns> public CustomAwaiter GetAwaiter() { return new CustomAwaiter(_completeSynchronously); } } /// <summary> /// 类型A 实现了 System.Runtime.CompilerServices.INotifyCompletion 接口 /// </summary> class CustomAwaiter : INotifyCompletion { private string _result = "Completed synchronously"; private readonly bool _completeSynchronously; /// <summary> /// A有一个可访问的、可读的类型为bool的实例属性IsCompleted /// 如果IsCompleted属性返回true,则只需同步调用GetResult方法 /// </summary> public bool IsCompleted => _completeSynchronously; public CustomAwaiter(bool completeSynchronously) { _completeSynchronously = completeSynchronously; } /// <summary> /// A有一个名为GetResult的可访问的实例方法,该方法没有任何参数和类型参数。 /// </summary> /// <returns></returns> public string GetResult() { return _result; } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(state => { Thread.Sleep(TimeSpan.FromSeconds(1)); _result = GetInfo(); continuation?.Invoke(); }); } private string GetInfo() { return $"Task is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " + $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}"; } }
await 的异步方法的刨析
通过一段代码来了解await,把这编译后,用ILspy 反编译。
namespace MyTask; class Program { public static void Main(string[] args) { Task<string> baconTask = FryBaconAsync(3); baconTask.ContinueWith(t =>Console.WriteLine(t.Result)); Console.Read(); } static async Task<string> FryBaconAsync(int slices) { HttpClient httpClient=new HttpClient(); string content = await httpClient.GetStringAsync("https://www.cnblogs.com/cdaniu/p/15681416.html"); return content; //整数3和Task<int>不存在隐形转化啊,怎么就可以return 3; 如果你也存在这个疑问 请继续往下阅读,接下去详细分析。 } }
用ILspy 反编译后的完整代码:

// MyTask.Program using System; using System.Diagnostics; using System.Net.Http; using System.Runtime.CompilerServices; using System.Threading.Tasks; using MyTask; [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] internal class Program { [Serializable] [CompilerGenerated] private sealed class <>c { [System.Runtime.CompilerServices.Nullable(0)] public static readonly <>c <>9 = new <>c(); [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1 })] public static Action<Task<string>> <>9__0_0; internal void <Main>b__0_0(Task<string> t) { Console.WriteLine(t.Result); } } [CompilerGenerated] private sealed class <FryBaconAsync>d__1 : IAsyncStateMachine { public int <>1__state; [System.Runtime.CompilerServices.Nullable(0)] public AsyncTaskMethodBuilder<string> <>t__builder; public int slices; [System.Runtime.CompilerServices.Nullable(0)] private HttpClient <httpClient>5__1; [System.Runtime.CompilerServices.Nullable(0)] private string <content>5__2; [System.Runtime.CompilerServices.Nullable(0)] private string <>s__3; [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] private TaskAwaiter<string> <>u__1; private void MoveNext() { int num = <>1__state; string result; try { TaskAwaiter<string> awaiter; if (num != 0) { <httpClient>5__1 = new HttpClient(); awaiter = <httpClient>5__1.GetStringAsync("https://www.cnblogs.com/cdaniu/p/15681416.html").GetAwaiter(); if (!awaiter.IsCompleted) { num = (<>1__state = 0); <>u__1 = awaiter; <FryBaconAsync>d__1 stateMachine = this; <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); return; } } else { awaiter = <>u__1; <>u__1 = default(TaskAwaiter<string>); num = (<>1__state = -1); } <>s__3 = awaiter.GetResult(); <content>5__2 = <>s__3; <>s__3 = null; result = <content>5__2; } catch (Exception exception) { <>1__state = -2; <httpClient>5__1 = null; <content>5__2 = null; <>t__builder.SetException(exception); return; } <>1__state = -2; <httpClient>5__1 = null; <content>5__2 = null; <>t__builder.SetResult(result); } void IAsyncStateMachine.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext this.MoveNext(); } [DebuggerHidden] private void SetStateMachine(IAsyncStateMachine stateMachine) { } void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) { //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine this.SetStateMachine(stateMachine); } } public static void Main(string[] args) { Task<string> baconTask = FryBaconAsync(3); baconTask.ContinueWith(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Action<Task<string>>(<>c.<>9.<Main>b__0_0))); Console.Read(); } [AsyncStateMachine(typeof(<FryBaconAsync>d__1))] [DebuggerStepThrough] private static Task<string> FryBaconAsync(int slices) { <FryBaconAsync>d__1 stateMachine = new <FryBaconAsync>d__1(); stateMachine.<>t__builder = AsyncTaskMethodBuilder<string>.Create(); stateMachine.slices = slices; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } }
编译器根据await生成一个等待器awaiter,用这个awaiter 等待异步方法运行的结果。然后程序通过return;把控制权还给了调用函数,
可等待的数据类型-Awaitable Type
编译器采用鸭子类型来判断可等待类型。即一个Type包含 public WorkItemAwaiter GetAwaiter()方法就是可等待类型。返回值WorkItemAwaiter的类型必须继承INotifyComplete接口和有 public void GetResult() 方法、 public bool IsCompleted{get;}属性。和枚举器(Enumerable、Enumerator)的原理一样
自定义一个可等待的数据类型 WorkItem
using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; Debug.WriteLine("sfsdfs"); Test(); async WorkItem Test() { await new WorkItem(); } public class WorkItem { public WorkItemAwaiter GetAwaiter() { return new WorkItemAwaiter(this); } internal volatile int m_StateFlag; public bool IsCompleted { get { int stateFlag = m_StateFlag; return IsCompletedMethod(stateFlag); } } private bool IsCompletedMethod(int stateFlag) { //判断完成 return (stateFlag & (int)TestStateFlag.Completed) != 0; } // m_StateFlag的常量 internal enum TestStateFlag { Start = 0x0001, // bin: 0000 0000 0000 0000 0000 0000 0000 0001 Running = 0x0002, // bin: 0000 0000 0000 0000 0000 0000 0000 0010 Waiting = 0x0004, // bin: 0000 0000 0000 0000 0000 0000 0000 0100 Completed = 0x0008, // bin: 0000 0000 0000 0000 0000 0000 0000 1000 WaitCompleteNotifyed = 0x0010, // bin: 0000 0000 0000 0000 0000 0000 0001 0000 } // internal bool IsWaitNotificationEnabledOrNotCompleted => (m_StateFlag & ((int)TestStateFlag.WaitCompleteNotifyed | (int)TestStateFlag.Completed)) != (int)TestStateFlag.Completed; } /// <summary> /// /// </summary> public class WorkItemAwaiter : ICriticalNotifyCompletion { internal readonly WorkItem m_WorkItem; public WorkItemAwaiter(WorkItem workItem) { this.m_WorkItem = workItem; } public bool IsCompleted=> m_WorkItem.IsCompleted; public void OnCompleted(Action continuation) { throw new NotImplementedException(); } public void UnsafeOnCompleted(Action continuation) { throw new NotImplementedException(); } public void GetResult() { ValidateEnd(m_WorkItem); } /// <summary> ///快速检查一个await操作是否结束,以确定在完成await操作之前是否需要做更多的操作。 /// </summary> /// <param name="task">The awaited task.</param> internal static void ValidateEnd(WorkItem workItem) { // 快速检测 if (workItem.IsWaitNotificationEnabledOrNotCompleted) { } } internal void SpinUntilCompleted() { // Spin wait until the completion is finalized by another thread. SpinWait sw = default; while (!IsCompleted) { sw.SpinOnce(); } } }