Kru*_*lur 11 c# task-parallel-library async-await xamarin
在下面的示例中await
,使用了两个调用.为了获得性能,样本会被转换Task.WaitAll()
(实际上并不是更快,但这只是一个例子).
这是来自Android上使用Sqlite.Net的库中的代码,该方法从OnResume()
主UI线程调用:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Run Code Online (Sandbox Code Playgroud)
这是替代方案:
public void SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
Task.WaitAll(t1, t2);
}
Run Code Online (Sandbox Code Playgroud)
但是从我的理解Task.WaitAll()
应该在等待时阻止UI线程,从而导致死锁.但它的工作正常.那是因为这两个调用实际上并没有在UI线程上调用任何东西吗?
如果我使用它有什么区别Task.WhenAll()
?我猜它即使会调用UI线程也能工作,就像使用它一样await
.
Ste*_*ary 16
我在博客上描述了死锁情况的细节.我也有一篇MSDN文章SynchronizationContext
,你可能会觉得有帮助.
总之,Task.WaitAll
在您的方案中会出现死锁,但前提是任务需要同步回UI线程才能完成.您可以得出结论,CreateTableAsync<T>()
不会同步回UI线程.
相反,这段代码会死锁:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Task.WaitAll(SetupDatabaseAsync());
Run Code Online (Sandbox Code Playgroud)
我建议你不要阻止异步代码; 在async
世界上,同步回到上下文是默认行为(正如我在我的async
介绍中描述的那样),因此很容易意外地做到这一点.未来对Sqlite.Net的一些更改可能(意外地)同步回原始上下文,然后使用Task.WaitAll
与原始示例类似的任何代码将突然死锁.
最好使用async
"一路":
public Task SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
return Task.WhenAll(t1, t2);
}
Run Code Online (Sandbox Code Playgroud)
"异步一直"是我在异步最佳实践文章中推荐的指南之一.