在同一个任务上使用多个等待应该小心。我在尝试使用BlockingCollection.GetConsumingEnumerable()方法时遇到过这种情况。最终得到这个简化的测试。
class TestTwoAwaiters
{
public void Test()
{
var t = Task.Delay(1000).ContinueWith(_ => Utils.WriteLine("task complete"));
var w1 = FirstAwaiter(t);
var w2 = SecondAwaiter(t);
Task.WaitAll(w1, w2);
}
private async Task FirstAwaiter(Task t)
{
await t;
//await t.ContinueWith(_ => { });
Utils.WriteLine("first wait complete");
Task.Delay(3000).Wait(); // execute blocking operation
}
private async Task SecondAwaiter(Task t)
{
await t;
Utils.WriteLine("second wait complete");
Task.Delay(3000).Wait(); // execute blocking operation
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这里的问题是任务的延续将因此在一个线程上执行订阅者。如果一个等待者执行阻塞操作(例如从 中产生BlockingCollection.GetConsumingEnumerable()),它将阻塞其他等待者并且他们无法继续他们的工作。ContinueWith()我认为一个可能的解决方案是在等待任务之前调用。它将把延续分成两部分,并且阻塞操作将在新线程上执行。
有人可以确认或反驳多次等待任务的可能性吗?如果这种情况很常见,那么绕过阻塞的正确方法是什么?