- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文为系列博客 。
上文我们学习了 await 这个语法糖背后的实现,了解了 await 这个关键词是如何去等待 Task 的完成并获取 Task 执行结果。并且我们还实现了一个简单的 awaitable 类型,它可以让我们自定义 await 的行为.
class FooAwaitable<TResult>
{
// 回调,简化起见,未将其包裹到 TaskContinuation 这样的容器里
private Action _continuation;
private TResult _result;
private Exception _exception;
private volatile bool _completed;
public bool IsCompleted => _completed;
// Awaitable 中的关键部分,提供 GetAwaiter 方法
public FooAwaiter<TResult> GetAwaiter() => new FooAwaiter<TResult>(this);
public void Run(Func<TResult> func)
{
new Thread(() =>
{
var result = func();
TrySetResult(result);
})
{
IsBackground = true
}.Start();
}
private bool AddFooContinuation(Action action)
{
if (_completed)
{
return false;
}
_continuation += action;
return true;
}
internal void TrySetResult(TResult result)
{
_result = result;
_completed = true;
_continuation?.Invoke();
}
internal void TrySetException(Exception exception)
{
_exception = exception;
_completed = true;
_continuation?.Invoke();
}
// 1 实现 ICriticalNotifyCompletion
public struct FooAwaiter<TResult> : ICriticalNotifyCompletion
{
private readonly FooAwaitable<TResult> _fooAwaitable;
// 2 实现 IsCompleted 属性
public bool IsCompleted => _fooAwaitable.IsCompleted;
public FooAwaiter(FooAwaitable<TResult> fooAwaitable)
{
_fooAwaitable = fooAwaitable;
}
public void OnCompleted(Action continuation)
{
Console.WriteLine("FooAwaiter.OnCompleted");
if (_fooAwaitable.AddFooContinuation(continuation))
{
Console.WriteLine("FooAwaiter.OnCompleted: added continuation");
}
else
{
Console.WriteLine("FooAwaiter.OnCompleted: already completed, invoking continuation");
continuation();
}
}
public void UnsafeOnCompleted(Action continuation)
{
Console.WriteLine("FooAwaiter.UnsafeOnCompleted");
if (_fooAwaitable.AddFooContinuation(continuation))
{
Console.WriteLine("FooAwaiter.UnsafeOnCompleted: added continuation");
}
else
{
Console.WriteLine("FooAwaiter.UnsafeOnCompleted: already completed, invoking continuation");
continuation();
}
}
// 3. 实现 GetResult 方法
public TResult GetResult()
{
if (_fooAwaitable._exception != null)
{
// 4. 如果 awaitable 中有异常,则抛出
throw _fooAwaitable._exception;
}
Console.WriteLine("FooAwaiter.GetResult");
return _fooAwaitable._result;
}
}
}
如果在一个方法中使用了 await,那么这个方法就必须添加 async 修饰符。并且这个方法的返回类型通常是 Task 或者 其它 runtime 里定义的 awaitable 类型.
int foo = await FooAsync();
Console.WriteLine(foo); // 1
async Task<int> FooAsync()
{
await Task.Delay(1000);
return 1;
}
问题1: 上面的代码中,FooAsync 方法是一个异步方法,它的返回类型是 Task 。但代码中的 await FooAsync() 并不会返回 Task ,而是返回 int。这是为什么呢?
如果我们把 FooAsync 的返回值改成我们自己实现的 awaitable 类型,编译器会报错:
问题2: 明明我们可以在 FooAwaitable 实例上使用 await 关键词,为什么把它作为 FooAsync 的返回类型就会报错呢?且提示它不是一个 task-like 类型?
实际上我们在上篇文章实现的 awaitable 类型 FooAwaitable,只是支持了 await 关键词,并不是一个完整的 task-like 类型.
而上面两个问题的答案就是本文要讲的内容: AsyncMethodBuilder .
引用上一篇文章介绍状态机的代码:
class Program
{
static async Task Main(string[] args)
{
var a = 1;
Console.WriteLine(await FooAsync(a));
}
static async Task<int> FooAsync(int a)
{
int b = 2;
int c = await BarAsync();
return a + b + c;
}
static async Task<int> BarAsync()
{
await Task.Delay(100);
return 3;
}
}
由 FooAsync 编译成的 IL 代码经整理后的等效 C# 代码如下:
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var a = 1;
Console.WriteLine(await FooAsync(a));
}
static Task<int> FooAsync(int a)
{
var stateMachine = new FooStateMachine
{
_asyncTaskMethodBuilder = AsyncTaskMethodBuilder<int>.Create(),
_state = -1, // 初始化状态
_a = a // 将实参拷贝到状态机字段
};
// 开始执行状态机
stateMachine._asyncTaskMethodBuilder.Start(ref stateMachine);
return stateMachine._asyncTaskMethodBuilder.Task;
}
static async Task<int> BarAsync()
{
await Task.Delay(100);
return 3;
}
public class FooStateMachine : IAsyncStateMachine
{
// 方法的参数和局部变量被编译会字段
public int _a;
public AsyncTaskMethodBuilder<int> _asyncTaskMethodBuilder;
private int _b;
private int _c;
// -1: 初始化状态
// 0: 等到 Task 执行完成
// -2: 状态机执行完成
public int _state;
private TaskAwaiter<int> _taskAwaiter;
public void MoveNext()
{
var result = 0;
TaskAwaiter<int> taskAwaiter;
try
{
// 状态不是0,代表 Task 未完成
if (_state != 0)
{
// 初始化局部变量
_b = 2;
taskAwaiter = Program.BarAsync().GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
// state: -1 => 0,异步等待 Task 完成
_state = 0;
_taskAwaiter = taskAwaiter;
var stateMachine = this;
// 内部会调用 将 stateMachine.MoveNext 注册为 Task 的回调
_asyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref taskAwaiter, ref stateMachine);
return;
}
}
else
{
taskAwaiter = _taskAwaiter;
// TaskAwaiter 是个结构体,这边相当于是个清空 _taskAwaiter 字段的操作
_taskAwaiter = new TaskAwaiter<int>();
// state: 0 => -1,状态机恢复到初始化状态
_state = -1;
}
_c = taskAwaiter.GetResult();
result = _a + _b + _c;
}
catch (Exception e)
{
// state: any => -2,状态机执行完成
_state = -2;
_asyncTaskMethodBuilder.SetException(e);
return;
}
// state: -1 => -2,状态机执行完成
_state = -2;
// 将 result 设置为 FooAsync 方法的返回值
_asyncTaskMethodBuilder.SetResult(result);
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}
}
在编译器生成的状态机类中,我们可以看到一个名为 _asyncTaskMethodBuilder 的字段,它的类型是 AsyncTaskMethodBuilder<int>。 这个 AsyncTaskMethodBuilder 就是 Task所绑定的 AsyncMethodBuilder.
以 AsyncTaskMethodBuilder<TResult> 为例,我们来看下 AsyncMethodBuilder 的结构:
public struct AsyncTaskMethodBuilder<TResult>
{
// 保存最后作为返回值的 Task
private Task<TResult>? m_task;
// 创建一个 AsyncTaskMethodBuilder
public static AsyncTaskMethodBuilder<TResult> Create() => default;
// 开始执行 AsyncTaskMethodBuilder 及其绑定的状态机
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
AsyncMethodBuilderCore.Start(ref stateMachine);
// 绑定状态机,但编译器的编译结果不会调用
public void SetStateMachine(IAsyncStateMachine stateMachine) =>
AsyncMethodBuilderCore.SetStateMachine(stateMachine, m_task);
// 将状态机的 MoveNext 方法注册为 async方法 内 await 的 Task 的回调
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
// 同上,参考前一篇文章讲 UnsafeOnCompleted 和 OnCompleted 的区别
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
public Task<TResult> Task
{
get => m_task ?? InitializeTaskAsPromise();
}
public void SetResult(TResult result)
{
if (m_task is null)
{
m_task = Threading.Tasks.Task.FromResult(result);
}
else
{
SetExistingTaskResult(m_task, result);
}
}
public void SetException(Exception exception) => SetException(exception, ref m_task);
}
非泛型的 Task 对应的 AsyncMethodBuilder 是 AsyncTaskMethodBuilder,它的结构与泛型的 AsyncTaskMethodBuilder<TResult> 类似,但因为最终返回的 Task 没有执行结果,它的 SetResult 只是为了标记 Task 的完成状态并触发 Task 的回调.
public struct AsyncTaskMethodBuilder
{
private Task<VoidTaskResult>? m_task;
public static AsyncTaskMethodBuilder Create() => default;
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
AsyncMethodBuilderCore.Start(ref stateMachine);
public void SetStateMachine(IAsyncStateMachine stateMachine) =>
AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: null);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
public Task Task
{
get => m_task ?? InitializeTaskAsPromise();
}
public void SetResult()
{
if (m_task is null)
{
m_task = Task.s_cachedCompleted;
}
else
{
AsyncTaskMethodBuilder<VoidTaskResult>.SetExistingTaskResult(m_task, default!);
}
}
public void SetException(Exception exception) =>
AsyncTaskMethodBuilder<VoidTaskResult>.SetException(exception, ref m_task);
}
AsyncTaskMethodBuilder 在 FooAsync 方法的执行过程中,起到了以下作用:
为了方便说明,下文我们将 FooAsync 方法返回的 Task 称为 FooTask,BarAsync 方法返回的 Task 称为 BarTask.
状态机通过 _asyncTaskMethodBuilder.Start 方法来启动且其 MoveNext 方式是通过 _asyncTaskMethodBuilder.AwaitUnsafeOnCompleted 方法来注册为 BarTask 的回调的.
_asyncTaskMethodBuilder 是用来构建一个 Task 对象,_asyncTaskMethodBuilder 的 Task 属性就是 FooAsync 方法返回的 FooTask。通过 _asyncTaskMethodBuilder 的 SetResult 方法,我们可以设置 FooTask 的执行结果, 通过 SetException 方法,我们可以设置 FooTask 的异常.
一个 AsyncMethodBuilder 是由下面几个部分组成的:
为了让 async 方法适配传统的事件回调,C# 引入了 async void 的概念.
var foo = new Foo();
foo.OnSayHello += FooAsync;
foo.SayHello();
Console.ReadLine();
async void FooAsync(object sender, EventArgs e)
{
var args = e as SayHelloEventArgs;
await Task.Delay(1000);
Console.WriteLine(args.Message);
}
class Foo
{
public event EventHandler OnSayHello;
public void SayHello()
{
OnSayHello.Invoke(this, new SayHelloEventArgs { Message = "Hello" });
}
}
class SayHelloEventArgs : EventArgs
{
public string Message { get; set; }
}
async void 也有一个对应的 AsyncVoidMethodBuilder.
public struct AsyncVoidMethodBuilder
{
// AsyncVoidMethodBuilder 是对 AsyncTaskMethodBuilder 的封装
private AsyncTaskMethodBuilder _builder;
public static AsyncVoidMethodBuilder Create()
{
// ...
}
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
AsyncMethodBuilderCore.Start(ref stateMachine);
public void SetStateMachine(IAsyncStateMachine stateMachine) =>
_builder.SetStateMachine(stateMachine);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_builder.AwaitOnCompleted(ref awaiter, ref stateMachine);
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
public void SetResult()
{
// 仅仅是做 runtime 的一些状态标记
}
public void SetException(Exception exception)
{
// 这个异常只能通过 TaskScheduler.UnobservedTaskException 事件来捕获
}
// 因为没有返回值,这个 Task 不对外暴露
private Task Task => _builder.Task;
}
自定义一个 AsyncMethodBuilder,不需要实现任意接口,只需要实现上面说的那 6 个主要组成部分,编译器就能够正常编译.
awaitable 绑定 AsyncMethodBuilder 的方式有两种:
struct FooAsyncMethodBuilder<TResult>
{
private FooAwaitable<TResult> _awaitable;
// 1. 定义 Task 属性
public FooAwaitable<TResult> Task
{
get
{
Console.WriteLine("FooAsyncMethodBuilder.Task");
return _awaitable;
}
}
// 2. 定义 Create 方法
public static FooAsyncMethodBuilder<TResult> Create()
{
Console.WriteLine("FooAsyncMethodBuilder.Create");
var awaitable = new FooAwaitable<TResult>();
var builder = new FooAsyncMethodBuilder<TResult>
{
_awaitable = awaitable,
};
return builder;
}
// 3. 定义 Start 方法
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
Console.WriteLine("FooAsyncMethodBuilder.Start");
stateMachine.MoveNext();
}
// 4. 定义 AwaitOnCompleted/AwaitUnsafeOnCompleted 方法
// 如果 awaiter 实现了 INotifyCompletion 接口,就调用 AwaitOnCompleted 方法
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
Console.WriteLine("FooAsyncMethodBuilder.AwaitOnCompleted");
awaiter.OnCompleted(stateMachine.MoveNext);
}
[SecuritySafeCritical]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter,
ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
Console.WriteLine("FooAsyncMethodBuilder.AwaitUnsafeOnCompleted");
awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
}
// 5. 定义 SetResult/SetException 方法
public void SetResult(TResult result)
{
Console.WriteLine("FooAsyncMethodBuilder.SetResult");
_awaitable.TrySetResult(result);
}
public void SetException(Exception exception)
{
Console.WriteLine("FooAsyncMethodBuilder.SetException");
_awaitable.TrySetException(exception);
}
// 6. 定义 SetStateMachine 方法,虽然编译器不会调用,但是编译器要求必须有这个方法
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
Console.WriteLine("FooAsyncMethodBuilder.SetStateMachine");
}
}
// 7. 通过 AsyncMethodBuilderAttribute 绑定 FooAsyncMethodBuilder
[AsyncMethodBuilder(typeof(FooAsyncMethodBuilder<>))]
class FooAwaitable<TResult>
{
// ...
}
Console.WriteLine("await Foo1Async()");
int foo1= await Foo1Async();
Console.WriteLine("Foo1Async() result: " + foo1);
Console.WriteLine();
Console.WriteLine("await Foo2Async()");
int foo2 = await Foo2Async();
Console.WriteLine("Foo2Async() result: " + foo2);
Console.WriteLine();
Console.WriteLine("await FooExceptionAsync()");
try
{
await FooExceptionAsync();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
async FooAwaitable<int> Foo1Async()
{
await Task.Delay(1000);
return 1;
}
// 覆盖默认的 AsyncMethodBuilder,使用 FooAsyncMethodBuilder2
// 本文省略了 FooAsyncMethodBuilder2 的定义,可以参考上面的 FooAsyncMethodBuilder
[AsyncMethodBuilder(typeof(FooAsyncMethodBuilder2<>))]
async FooAwaitable<int> Foo2Async()
{
await Task.Delay(1000);
return 2;
}
执行结果:
await Foo1Async() FooAsyncMethodBuilder.Create FooAsyncMethodBuilder.Start FooAsyncMethodBuilder.AwaitUnsafeOnCompleted FooAsyncMethodBuilder.Task FooAwaiter.UnsafeOnCompleted FooAwaiter.UnsafeOnCompleted: added continuation FooAsyncMethodBuilder.SetResult FooAwaiter.GetResult Foo1Async() result: 1 await Foo2Async() FooAsyncMethodBuilder2.Create FooAsyncMethodBuilder2.Start FooAsyncMethodBuilder2.AwaitUnsafeOnCompleted FooAsyncMethodBuilder2.Task FooAwaiter.UnsafeOnCompleted FooAwaiter.UnsafeOnCompleted: added continuation FooAsyncMethodBuilder2.SetResult FooAwaiter.GetResult Foo2Async() result: 2 await FooExceptionAsync() FooAsyncMethodBuilder.Create FooAsyncMethodBuilder.Start FooAsyncMethodBuilder.AwaitUnsafeOnCompleted FooAsyncMethodBuilder.Task FooAwaiter.UnsafeOnCompleted FooAwaiter.UnsafeOnCompleted: added continuation FooAsyncMethodBuilder.SetException Exception from FooExceptionAsync
在方法上添加 AsyncMethodBuilderAttribute 的功能是后来才添加的,通过这个功能,可以覆盖 awaitable 类型上的 AsyncMethodBuilderAttribute,以便进行性能优化。例如 .NET 6 开始提供的 PoolingAsyncValueTaskMethodBuilder,对原始的 AsyncValueTaskMethodBuilder 进行了池化处理,可以通过在方法上添加 AsyncMethodBuilderAttribute 来使用.
欢迎关注个人技术公众号 。
最后此篇关于.NETTask揭秘(3)async与AsyncMethodBuilder的文章就讲到这里了,如果你想了解更多关于.NETTask揭秘(3)async与AsyncMethodBuilder的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
前言 Vue和Vite之父尤雨溪宣布成立公司 VoidZero,目前已经融资3200万。这篇文章欧阳将带你了解VoidZero是如何改变javascript的世界! 关注公众号:【前端欧阳】,给自
前言 TimerQueue 是.NET中实现定时任务的核心组件,它是一个定时任务的管理器,负责存储和调度定时任务。它被用于实现很多 .NET 中的定时任务,比如 System.Threadin
网站服务器这类问题我相信很多朋友讲过,但为什么他和网站优化还有关系呢?那么请您读读我写的没有文笔的文章,看看是否有所认同。 是的,服务器其实也是一个优化网站的最大杀手也是最大帮手,现今万网与阿里云
这个问题在这里已经有了答案: How does XPath deal with XML namespaces? (2 个回答) 5年前关闭。 我有这个 XML
在我们工作中无数次点击鼠标的时候,你有思考过鼠标是怎么工作的吗?在购买鼠标的时候你是怎么挑选的呢?看着那些标称的数据,你是否茫然过?那么如果小编现在说,其实每个鼠标都是一台优秀的“照相机”,你会相信
在 this question海报询问如何在一行中执行以下操作: sub my_sub { my $ref_array = shift; my @array = @$ref_array
我正在尝试了解 Javascript Lambda 方法,但我仍然对非常灵活的定义方式和变量范围感到非常困惑。 例如我正在研究以下插件的代码,除了代码中还有其他部分我不太清楚,我感兴趣的是代码是如何组
谁能帮我揭开以下表达式的神秘面纱: ++[[]][+[]]+[+[]] 我的理解从左到右: ++[[]]:不确定这将评估什么以及如何评估。 [+[]]:+[] 将首先执行,一元运算符将尝试将 [] 转
在 python 中,可以在多个进程之间共享 ctypes 对象。但是我注意到分配这些对象似乎非常昂贵。 考虑以下代码: from multiprocessing import sharedctype
我目前对 Glassfish 3.1.2.2 处理 EJB 的方式感到困惑。 我有一个 OSGi 项目,它由许多 OSGi 包(jar)组成。此外,还有一些 WAR,包括 Tapestry Web 应
这些天我在玩线程库并尝试实现一些功能。其中一个教程说要运行程序使用: gcc -lpthread -lrt -lc -lm project1.c scheduler.c -o out 首先我需要深入了
如 app.secret_key未设置,Flask 将不允许您设置或访问 session 字典。 这就是flask user guide has to say在这个问题上。 我对 Web 开发很陌生,
Ruby on Rails 新手问题... 考虑以下代码(在 View 中): | | 在 ERB 标签中调用的一些方法对我来说就像魔法一样,我正试图揭开它们的神秘面纱。如果我不了解代码
HTTPS 是建立在 SSL/TLS 传输层安全协议之上的一种 HTTP 协议,相当于 HTTPS = HTTP + SSL/TLS。第一篇文章 “HTTPS - 通俗易懂的阐述 HTTPS 协
本周新 Xcode 3.2.1 中包含的自述文件内容如下: 静态代码分析通过“构建”菜单下的“构建和分析”选项或通过自定义build设置完全集成在 Xcode IDE 中 GCC 4.2 是 10.6
是的,我知道。关于 NSOperation 世界有很多问题和答案,但我仍然有一些疑问。我会尝试用两部分的问题来解释我的疑虑。它们相互关联。 在 SO 帖子中 nsoperationqueue-and-
运行后,我看到我的应用程序在 TaskMgr 中占用了 3.5Gb 我在 Windbg 中看到的内容有点令人困惑: 0:022> !address -summary ProcessParametrs
我是一名优秀的程序员,十分优秀!