我在回答我自己的问题,因为我突然想起我知道答案。
当使用C#语言支持功能
它的状态机。
如果异步方法的实施者使用C#语言支持,如方法声明中的async
关键字和方法体内部的关键字await
等待该任务固有的操作,则在任务的范围内状态机通过设置任务的结果来通知任务完成。
例如,如果他的执行是这样:
// client code
public async void TopLevelMethod()
{
await MyMethodAsync();
}
// library code -- his implementation
public async Task MyMethodAsync()
{
await AnotherOperationAsync();
}
随后的MyMethodAsync
建成后,将委托给编译器生成的状态机。
当然,AnotherOperationAsync
的完成信号也将由编译器生成的状态机处理,但这不是重点。
产品召回MoveNext
方法中的状态表示任务完成状态和在MoveNext
调用延续回调内部的块,这还呼吁AsyncXXXMethodBuilder
SetResult
。
当不使用C#语言支持功能
然而,如果异步方法的实施者没有利用的C#语言特性,那么它是实施者的责任信号通过在TaskCompletionSource
对象上设置相关结果,例外或取消属性来完成任务。
例如,
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource<object>();
try
{
AnotherOperation();
tcs.SetResult();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
如果实施者没有使用TPL支持或使用旧.NET API调用另一个操作异步,然后过,它是实施者的责任,通过一个明确的设置任务的状态信号任务完成Try/SetResult/Exception
等方法。
例如,
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource...
var autoReseEvent = ...
ThreadPool.QueueUserWorkItem(new WaitCallback(() =>
{
/* Work */
Thread.SpinWait(1000);
tcs.SetResult(...);
autoResetEvent.Set();
};)...;
return tcs.Task;
}
一种不明智的案例
等待一个任务,当然,要使用await
关键字的最佳方式。但是,如果实施异步API,实施者会这样做:
public Task MyMethodAsync()
{
return Task.Run(...);
}
这会让他的API的消费者感到酸口,我想呢?
Task.Run
应该只能用于火灾并忘记您不关心任务完成时间点的情况。
的一个例外是,如果你使用await
关键字期待已久的由调用返回的任务Task.Run
,如下所示的代码片段,在这种情况下,你会使用的语言支持,在第一部分中描述。
public async Task MyMethodAsync()
{
await Task.Run(...);
}
你能解释downvote吗? –
我没有找到一个理由为什么有人应该投票的问题或答案,既然都是好的,但由OP本身,所以投了两个 –
@MrinalKamboj非常感谢。 :-) –