在下面的示例中await
,使用了两个调用。为了获得性能,示例将转换为示例Task.WaitAll()
(并非真的更快,但这只是一个示例)。
这是在Android上使用Sqlite.Net的库中的代码,该方法OnResume()
在主UI线程上调用:
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
。
我在博客上描述了僵局情况的细节。我也有一篇MSDN文章SynchronizationContext
,您可能会有所帮助。
总之,Task.WaitAll
将在您的方案中陷入僵局,但前提是任务需要同步回UI线程才能完成。您可以得出结论,CreateTableAsync<T>()
它不同步回UI线程。
相反,此代码将陷入僵局:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Task.WaitAll(SetupDatabaseAsync());
我建议您不要阻塞异步代码。在async
世界上,同步返回到上下文是默认行为(正如我在async
介绍中所描述的),因此很容易意外地做到这一点。将来对Sqlite.Net的某些更改可能会(偶然)同步回原始上下文,然后使用Task.WaitAll
类似原始示例的任何代码都会突然死锁。
最好async
一路使用:
public Task SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
return Task.WhenAll(t1, t2);
}
“一路异步”是我在异步最佳实践文章中推荐的准则之一。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句