我可以保证 运行nable task continuations 已经 运行 了吗?

Can I guarantee runnable task continuations have been run?

这是我正在处理的一段代码中显着减少的测试用例:

var i = 0;

var taskCompletionSource = new TaskCompletionSource<object>();
var task = taskCompletionSource.Task;

Task.Run(async () => 
{
    await task;
    i = 1;
});

// Synchronously complete `task`
taskCompletionSource.SetResult(null);

// ???

Console.WriteLine(i);

假设此代码 运行s 在 async 方法的上下文中,应该用什么替换 // ??? 以确保此代码打印 1 而不是 0?

我相信我理解为什么编写的程序总是打印 0 —— 代码正在同步执行,没有任何东西交给调度程序。但令我惊讶的是

await Task.Yield();

还不够。有点讽刺(但完全可以理解,因为它不涉及异步执行)

await task;

另一方面,

await Task.Delay(1);

似乎足够了,但我不清楚这是一个保证还是时间上的意外。

以另一种方式问这个问题:是否有我可以编写的任何(合理的)代码来保证 task 的所有延续在继续之前都有 运行?

Assuming that this code runs in the context of an async method

var i = 0;

await Task.Run(async () => 
{
    await task;
    i = 1;
});

Console.WriteLine(i);

var i = 0;

await task;
i = 1;

Console.WriteLine(i);

Can I guarantee runnable task continuations have been run?

通过await他们。

var i = 0;

var taskCompletionSource = new TaskCompletionSource<object>();
var task = taskCompletionSource.Task;

var continuation = Task.Run(async () => 
{
    await task;
    i = 1;
});

// Synchronously complete `task`
taskCompletionSource.SetResult(null);

// wait for the continuation
await continuation;

// ouputs 1
Console.WriteLine(i);

如果您使用的是异步方法,这会起作用。如果不是,请使其异步。你也可以在技术上阻止,(.Wait() 而不是 await)但是这会导致死锁,所以要小心。