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:TaskTask<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();
}
} }

【C# TAP 异步编程】二 、await运算符已经可等待类型Awaitable的更多相关文章

  1. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  2. 异步编程Async/await关键字

    异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ...

  3. 抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext

    长话短说,本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext 引言 C#异步编程语法糖async/await,使开发者很容易就能编写异步代码. ...

  4. 【C# TAP 异步编程】三、async\await的运作机理详解

    [原创] 本文只是个人笔记,很多错误,欢迎指出. 环境:vs2022  .net6.0 C#10 参考:https://blog.csdn.net/brook_shi/article/details/ ...

  5. 异步编程,await async入门

    网上很多异步编程的文章,提供一篇入门: 异步编程模型 .net支持3种异步编程模式: msdn:https://docs.microsoft.com/zh-cn/dotnet/standard/asy ...

  6. 【憩园】C#并发编程之异步编程(二)

    写在前面 前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法.本篇文章将对async和await这两个关键字进行深入探讨,研究其中的运行机制,实现编码效率与运行效率 ...

  7. .net 温故知新:【5】异步编程 async await

    1.异步编程 异步编程是一项关键技术,可以直接处理多个核心上的阻塞 I/O 和并发操作. 通过 C#.Visual Basic 和 F# 中易于使用的语言级异步编程模型,.NET 可为应用和服务提供使 ...

  8. C#~异步编程再续~await与async引起的w3wp.exe崩溃

    返回目录 最近怪事又开始发生了,IIS的应用程序池无做挂掉,都指向同一个矛头,async,threadPool,Task,还有一个System.NullReferenceException,所以这些都 ...

  9. C#异步编程二

    上一异步编程的博客还是在9月份的,最近事情也比较多,烦恼事情一个接着一个,一个人的周末除了无聊就剩无聊了,也只有写写博客来打发下这无聊的时光.原本想着尽快把异步编程这块总结一下,之前把委托异步算是总结 ...

随机推荐

  1. Cesium入门13 - Extras - 附加内容

    Cesium入门13 - Extras - 附加内容 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 剩下的代码 ...

  2. 右键没有word?excel?ppt?注解表该改改啦

    ✿[office 2019]office2010版本以上的都可以(例如:office 2010.office 2016.office 2019) 一.快速方法解决右键没有word: 在电脑桌面右键一个 ...

  3. python 统计工作簿中每个人名出现的次数

    工作簿 需求:统计人名出现的次数 代码: # coding=gbk import pandas as pd import re def extract_chinese(txt): pattern = ...

  4. HTML横向二级导航

    图片素材没有发,就一个logo还有一个Nav背景图. 效果 HTML <!DOCTYPE html> <html lang="zh-cn"> <hea ...

  5. BGP路由协议(Border Gateway Protocol)

    BGP路由协议(Border Gateway Protocol) 目录 BGP路由协议(Border Gateway Protocol) 一.BGP概述 1.自治系统(AS,autonomous sy ...

  6. Spring Cloud 源码分析之OpenFeign

    OpenFeign是一个远程客户端请求代理,它的基本作用是让开发者能够以面向接口的方式来实现远程调用,从而屏蔽底层通信的复杂性,它的具体原理如下图所示. 在今天的内容中,我们需要详细分析OpenFei ...

  7. 晋升挂了!leader说不是我技术不行

    大家好,我是对白. 今天给大家分享一位朋友在互联网大厂晋升失败的故事,不是每一位校招生第一年都可以稳稳晋升的,这不仅取决于你的业务收益,还取决于你是否会包装自己的项目,以下为原文. 晋升 去年秋季,我 ...

  8. java中最简单的计算执行时长的方式

    日常在做一些性能测试的时候会通过执行时间来判断执行时长,java中最简单的方式如下: //开始时间 long startL= new Date().getTime(); //这里需要导入 java.u ...

  9. 帆软报表(finereport)点击事件对话框打开

    点击事件对话框打开iframe var iframe = $("<iframe id='001' name='001' width='100%' height='100%' scrol ...

  10. log4j和lockback的比较,二者可否同时使用

    一.log4j和logback的介绍 log4j: 可以控制日志信息输送的目的地是控制台.文件.GUI组件,甚至是套接口服务器.NT的事件记录器.UNIX Syslog守护进程等:可以控制每一条日志的 ...