为什么 Task.WaitAll() 不会在这里阻塞或导致死锁? [英] Why does Task.WaitAll() not block or cause a deadlock here?

查看:58
本文介绍了为什么 Task.WaitAll() 不会在这里阻塞或导致死锁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的示例中,使用了两个 await 调用.为了提高性能,示例被转换为 Task.WaitAll()(实际上并没有更快,但这只是一个例子).

In the example below two await calls are used. To gain performance, the sample gets converted Task.WaitAll() instead (not really any faster, but this is just an example).

这是在 Android 上使用 Sqlite.Net 的库中的代码,该方法从主 UI 线程上的 OnResume() 调用:

This is code from a library using Sqlite.Net on Android and the method gets called from OnResume() on the main UI thread:

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 线程上调用任何内容吗?

But from my understanding Task.WaitAll() should block the UI thread while waiting, thus leading to a deadlock. But it works just fine. Is that because the two calls don't actually invoke anything on the UI thread?

如果我改用 Task.WhenAll() 有什么区别?我的猜测是,即使 UI 线程被调用,它也会工作,就像 await 一样.

What's the difference if I use Task.WhenAll() instead? My guess it that it would work even if the UI thread would be invoked, just like with await.

推荐答案

我描述了 僵局情况的详细信息 在我的博客上.我还有一篇关于 SynchronizationContextMSDN 文章,您可能会觉得有帮助.

I describe the details of the deadlock situation on my blog. I also have an MSDN article on SynchronizationContext that you may find helpful.

总而言之,Task.WaitAll 会在您的场景中死锁,但前提是任务需要同步回 UI 线程才能完成.您可以得出结论,CreateTableAsync() 不会同步回 UI 线程.

In summary, Task.WaitAll will deadlock in your scenario, but only if the tasks need to sync back to the UI thread in order to complete. You can conclude that CreateTableAsync<T>() does not sync back to the UI thread.

相反,这段代码会死锁:

In contrast, this code will deadlock:

public async Task SetupDatabaseAsync()
{
  await CreateTableAsync<Session>();
  await CreateTableAsync<Speaker>();
}

Task.WaitAll(SetupDatabaseAsync());

我建议您不要阻塞异步代码;在 async 世界中,同步回上下文是 默认 行为(正如我在我的 async intro),所以很容易不小心这样做.将来对 Sqlite.Net 的一些更改可能会(意外地)同步回原始上下文,然后任何像原始示例一样使用 Task.WaitAll 的代码都会突然死锁.

I recommend that you not block on asynchronous code; in the async world, sync'ing back to the context is the default behavior (as I describe in my async intro), so it's easy to accidentally do it. Some changes to Sqlite.Net in the future may (accidentally) sync back to the original context, and then any code using Task.WaitAll like your original example will suddenly deadlock.

最好一路"使用async:

public Task SetupDatabaseAsync()
{
  var t1 = CreateTableAsync<Session>();
  var t2 = CreateTableAsync<Speaker>();
  return Task.WhenAll(t1, t2);
}

全程异步"是我在我的异步最佳实践文章中推荐的准则之一一>.

"Async all the way" is one of the guidelines I recommend in my asynchronous best practices article.

这篇关于为什么 Task.WaitAll() 不会在这里阻塞或导致死锁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆