是创建Task一个上下文切换点,还是只在它开始await或做其他异步事情时?
例如,如果我有这些功能:
async Task Foo()
{
Console.WriteLine("In Foo");
await bar();
}
void CallFoo()
{
var task = Foo();
Console.WriteLine("Returned from Foo");
task.Wait();
}
Run Code Online (Sandbox Code Playgroud)
在"In Foo"之前,"从Foo返回"是否可以打印?
Eri*_*ert 11
在"In Foo"之前,"从Foo返回"是否可以打印?
在您编写的程序中,不,这是不可能的.
如果你有一个运行工作线程的不同程序,那么你就有了在线程之间排序副作用的所有常见问题."异步/等待"没有什么特别之处,这些问题就会消失.
创建一个Task是一个上下文切换点,还是只有当它开始等待或做其他异步事情时?
让我们通过"上下文切换点"的含义来准确.
C#中的方法可以执行以下四种操作之一:
标记的方法async可以暂停,但只有在await未完成的情况下才会暂停.等待完成的等待不会暂停,但它可以抛出.
async方法返回的任务很热门.也就是说,异步工作流程开始运行,直到它返回,抛出或挂起.可以使用Task构造函数创建"冷"任务,并且在您调用Start它之前不会启动.通常,除非您编写自己的任务调度程序,否则不会这样做.
请注意,这与迭代器块不同.一个常见的错误是:
IEnumerable<int> GetMeSomeInts(int x)
{
if (x < 0)
throw new SomeException();
for (int i = 0; i < x; i += i)
yield return i;
}
Run Code Online (Sandbox Code Playgroud)
如果你说
var nums = GetMeSomeInts(-1); // 1
foreach(int num in nums) // 2
...
Run Code Online (Sandbox Code Playgroud)
然后投掷不会发生在第1行,它发生在第2行!调用时,迭代器块不会运行到第一个yield.它们会立即暂停,直到迭代后才会执行foreach.要小心,特别是如果您在同一程序中使用异步和迭代程序协同程序.
10.15.1评估任务返回异步功能
调用任务返回异步函数会导致生成返回任务类型的实例.这称为异步函数的返回任务.该任务最初处于不完整状态.
然后评估异步函数体,直到它被挂起(通过到达await表达式)或终止,此时控制权与返回任务一起返回给调用者.
在问题的示例中,Foo将立即对其进行评估,直到await控制权返回给调用者."在Foo中"将始终在"从Foo返回"之前打印.