【发布时间】:2015-09-23 19:52:04
【问题描述】:
在同一个任务上使用多个等待应该小心。
我在尝试使用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
}
}
我认为这里的问题是任务的延续会在一个线程上执行订阅者。
如果一个等待者执行阻塞操作(例如从BlockingCollection.GetConsumingEnumerable() 产生),它将阻塞其他等待者并且他们无法继续工作。
我认为一个可能的解决方案是在等待任务之前调用ContinueWith()。
它将继续分为两部分,阻塞操作将在新线程上执行。
有人可以多次确认或反驳等待某项任务的可能性吗? 如果这很常见,那么绕过阻塞的正确方法是什么?
【问题讨论】:
-
你的代码代表什么问题?它运行没有问题。
-
问题是当一个等待者执行阻塞操作时,另一个不能做任何事情
-
你很可能阻塞了 UI 线程,它与单个任务上的多个等待无关,你会遇到与多个任务上的单个等待相同的问题。
-
您不应该在异步方法中执行长时间运行的同步操作。您有两种方法声称是异步的,但它们是同步运行的。不要那样做。
-
是的。但是其中一个等待者可以是一个专用循环,尽管等待的任务已经完成,但这个循环会阻塞其他等待者。
标签: c# async-await deadlock