在下面的示例中,使用了两个await
调用。为了获得性能,样本将被转换Task.WaitAll()
而不是更快(但这只是一个例子)。
这是来自Android上使用Sqlite.Net的库中的代码,该方法在主UI线程上从OnResume()
调用:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
这是替代方案:
public void SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
Task.WaitAll(t1, t2);
}
但是从我的理解Task.WaitAll()
应该在等待时阻止UI线程,从而导致死锁。但它的工作正常。那是因为这两个调用实际上并没有在UI线程上调用任何东西吗?
如果我使用Task.WhenAll()
,有什么区别?我猜它即使调用了UI线程也能正常工作,就像使用await
一样。
答案 0 :(得分:15)
我在博客上描述了details of the deadlock situation。我也有MSDN article on SynchronizationContext
您可能会觉得有帮助。
总之,Task.WaitAll
将在您的方案中死锁,但前提是任务需要同步回UI线程才能完成。您可以得出结论CreateTableAsync<T>()
没有同步回UI线程。
相反,这段代码会死锁:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Task.WaitAll(SetupDatabaseAsync());
我建议您不阻止异步代码;在async
世界中,同步回复上下文是默认行为(正如我在async
intro中所述),因此很容易不小心做了。未来对Sqlite.Net的一些更改可能(意外地)同步回原始上下文,然后使用Task.WaitAll
的任何代码都会像原始示例一样突然死锁。
最好一直使用async
&#34;&#34;:
public Task SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
return Task.WhenAll(t1, t2);
}
&#34;一路异步&#34;是我在asynchronous best practices article中推荐的指南之一。
答案 1 :(得分:0)
当您阻止UI线程(以及当前的同步上下文)时,如果您正在等待的其中一个任务将委托给当前上下文然后等待,那么它只会导致死锁它(同步或异步)。在任何异步方法上同步阻塞并不是每个案例中的即时死锁。
因为默认情况下,async
方法会将方法的其余部分封送到当前同步上下文和每个await
之后,并且因为任务将永远完成,直到发生这种情况,这意味着同步等待使用async/await
的方法通常会死锁;至少除非明确覆盖所描述的行为(通过,例如ConfigureAwait(false)
)。
使用WhenAll
表示您没有阻止当前的同步上下文。所有其他任务完成后,您只需要安排另一个继续运行,而不是阻止该线程,让上下文自由处理任何其他已准备就绪的请求(比如说, ,async
等待的基础WhenAll
方法的延续。
答案 2 :(得分:-1)
也许这个样本将展示可能发生的事情。这是一个iOS视图加载。尝试使用await调用和不使用它(下面已注释掉)。在函数中没有任何等待它将同步运行并且UI将被阻止。
public async override void ViewDidLoad()
{
base.ViewDidLoad ();
var d1 = Task.Delay (10);
var d2 = Task.Delay (10000);
//await Task.Delay (10);
Task.WaitAll (d1, d2);
this.label.Text = "Tasks have ended - really!";
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear (animated);
this.label.Text = "Tasks have ended - or have they?";
}