在用async包裹的方法体中,可以使用await关键字以同步的方式编写异步调用的代码。那么它的内部实现原理是什么样的呢?我们是否可以自定义await以实现定制性的需求呢?先来看一个简单的例子:
class Test {
public static void Main (string\[\] args) {
Task.Run (new Func<Task<string>>(task1));
Console.ReadLine ();
}
private async static Task<string> task1() {
string ret = await task2 ();
Console.WriteLine ("Await Task Result:" + ret);
return ret;
}
private static Task<string> task2() {
return Task.FromResult<string> ("Task2");
}
}
通过ILSpy反编译(要关闭"视图-选项-反编译await/async"菜单项),得到如下代码:
internal class Test
{
\[CompilerGenerated\]
\[StructLayout(LayoutKind.Auto)\]
private struct <task1>d\_\_0 : IAsyncStateMachine
{
public int <>1\_\_state;
public AsyncTaskMethodBuilder<string> <>t\_\_builder;
public string <ret>5\_\_1;
private TaskAwaiter<string> <>u\_\_$awaiter2;
private object <>t\_\_stack;
void IAsyncStateMachine.MoveNext()
{
string result;
try
{
int num = this.<>1\_\_state;
if (num != -)
{
TaskAwaiter<string> taskAwaiter;
if (num != )
{
taskAwaiter = Test.task2().GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
this.<>1\_\_state = ;
this.<>u\_\_$awaiter2 = taskAwaiter;
this.<>t\_\_builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, Test.<task1>d\_\_0>(ref taskAwaiter, ref this);
return;
}
}
else
{
taskAwaiter = this.<>u\_\_$awaiter2;
this.<>u\_\_$awaiter2 = default(TaskAwaiter<string>);
this.<>1\_\_state = -;
}
string arg\_86\_0 = taskAwaiter.GetResult();
taskAwaiter = default(TaskAwaiter<string>);
string text = arg\_86\_0;
this.<ret>5\_\_1 = text;
Console.WriteLine("Await Task Result:" + this.<ret>5\_\_1);
result = this.<ret>5\_\_1;
}
}
catch (Exception exception)
{
this.<>1\_\_state = -;
this.<>t\_\_builder.SetException(exception);
return;
}
this.<>1\_\_state = -;
this.<>t\_\_builder.SetResult(result);
}
\[DebuggerHidden\]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)
{
this.<>t\_\_builder.SetStateMachine(param0);
}
}
public static void Main(string\[\] args)
{
Task.Run<string>(new Func<Task<string>>(Test.task1));
Console.ReadLine();
}
\[DebuggerStepThrough, AsyncStateMachine(typeof(Test.<task1>d\_\_0))\]
private static Task<string> task1()
{
Test.<task1>d\_\_0 <task1>d\_\_;
<task1>d\_\_.<>t\_\_builder = AsyncTaskMethodBuilder<string>.Create();
<task1>d\_\_.<>1\_\_state = -;
AsyncTaskMethodBuilder<string> <>t\_\_builder = <task1>d\_\_.<>t\_\_builder;
<>t\_\_builder.Start<Test.<task1>d\_\_0>(ref <task1>d\_\_);
return <task1>d\_\_.<>t\_\_builder.Task;
}
private static Task<string> task2()
{
return Task.FromResult<string>("Task2");
}
}
按照代码的调用顺序,我们关注下task1()的内部实现。
首先是初始化结构体
了解了
这里要顺便提一句,在本例中,通过Task.Run创建了taskX1,await之后的代码与taskX1没有任何关系,从编译器生成的代码来看,在调用task1()方法并调用
由以上分析可以看到,async/await只是一个语法糖,async告知编译器要生成状态机代码,await则是配合生成GetAwaiter(),并封装跳转的用户代码块。除此之外,async/await与Task没有任何直接关系。而TaskAwaiter的作用,是实现INotifyCompletion(在System.Runtime.CompilerServices命名空间)以桥接异步回调过程。那么第二个自定义await的问题便一目了然了:任何类型,只需要实现GetAwaiter()方法以返回INotifyCompletion实例,便可以被await。
举个例子:
class TestAwaiter<T> : INotifyCompletion {
private T result;
private Action continuation;
// INotifyCompletion Implement
public void OnCompleted(Action continuation) { this.continuation = continuation; }
// Compiler Call Methods
public bool IsCompleted { get; private set; }
public T GetResult() { return result; }
public TestAwaiter<T> GetAwaiter() { return this; }
// Self Call Methods
public void SetResult(T ret) {
result = ret;
if (continuation != null) {
continuation ();
}
}
}
class Test {
public static void Main (string\[\] args) {
Task.Run (new Action(task1));
Console.ReadLine ();
}
private async static void task1() {
Console.WriteLine ("Begin await:");
int ret = await testAwaiter ();
Console.WriteLine ("Await Task Result:" + ret);
}
private static TestAwaiter<int> testAwaiter() {
TestAwaiter<int> awaiter = new TestAwaiter<int> ();
ThreadPool.QueueUserWorkItem (\_ => {
Thread.Sleep();
awaiter.SetResult ();
});
return awaiter;
}
}
这里没有再定义单独的类型以返回TestAwaiter,而是把二者都封装在了TestAwaiter内部。运行结果如下:
Begin await:
Await Task Result:100
手机扫一扫
移动阅读更方便
你可能感兴趣的文章