当前位置: 首页 > 编程语言 > C#

Task.WaitAll()为什么不阻塞导致死锁?分享

时间:2023-04-11 03:40:01 C#

为什么Task.WaitAll()不会阻塞或导致死锁?在下面的示例中,使用了两个await调用。为了提高性能,该示例转换为Task.WaitAll()(实际上并不快,但这只是一个示例)。这是来自使用Sqlite.Net的Android库的代码,该方法是从主UI线程上的OnResume()调用的:等待CreateTableAsync();}这是替代方案:publicvoidSetupDatabaseAsync(){vart1=CreateTableAsync();vart2=CreateTableAsync();任务.WaitAll(t1,t2);但是根据我的理解,Task.WaitAll()应该在等待时阻塞UI线程,从而导致死锁。但它工作正常。那是因为这两个调用实际上并没有在UI线程上调用任何东西吗?如果我改用Task.WhenAll()有什么区别?我猜它甚至在调用UI线程时也能工作,比如await。我在我的博客上描述了死锁情况的细节。我还有一篇关于SynchronizationContext的MSDN文章,您可能会发现它有帮助。总之,Task.WaitAll在你的场景中会死锁,但是Task.WaitAll是一个任务,需要同步回UI线程才能完成。您可以得出结论,CreateTableAsync()不会同步回UI线程。相反,此代码将死锁:publicasyncTaskSetupDatabaseAsync(){awaitCreateTableAsync();等待CreateTableAsync();}Task.WaitAll(SetupDatabaseAsync());我建议你不要阻止异步代码;在异步世界中,sync返回上下文是默认行为(正如我在异步简介中所描述的),因此很容易不小心这样做。对Sqlite.Net的一些未来更改可能(意外地)同步回原始上下文,然后任何使用Task.WaitAll的代码突然像原始示例一样死锁。最好“始终”使用异步:publicTaskSetupDatabaseAsync(){vart1=CreateTableAsync();vart2=CreateTableAsync();返回Task.WhenAll(t1,t2);"asyncalways"是我在async文章中推荐的最佳实践指南之一。当您阻塞UI线程(和当前同步上下文)时,如果您正在等待的任务之一将委托给当前上下文然后等待它(同步或异步),它只会导致死锁。在任何情况下,同步阻塞任何异步方法都不是即时死锁。因为默认情况下,async方法会将方法的其余部分编组到当前同步上下文并每次单独等待,并且因为在此之前任务永远不会完成,这意味着使用async/await方法的同步等待经常会死锁;至少除非所描述的行为被显式覆盖(通过,例如ConfigureAwait(false))。使用WhenAll意味着您不会阻塞当前同步上下文。当所有其他任务完成时,线程不再被阻塞,而只是安排另一个继续,让上下文空闲以处理现在准备好的任何其他请求(例如,当从底层异步方法继续WhenAll等待时)。也许这个示例将展示什么是可能的。这是一个iOS视图加载。尝试使用await和不使用它进行调用(在下面注释掉)。如果该函数中没有任何等待,它将同步运行并且UI将被阻止。以上是C#学习教程:Task.WaitAll()为什么不阻塞或导致死锁?如果分享的内容对你有用,需要了解更多C#学习教程,希望你多多关注——publicasyncoverridevoidViewDidLoad(){base.ViewDidLoad();vard1=Task.Delay(10);vard2=Task.Delay(10000);//等待任务。延迟(10);任务.WaitAll(d1,d2);this.label.Text="任务已经结束-真的!";}publicoverridevoidViewWillAppear(boolanimated){base.ViewWillAppear(animated);this.label.Text="任务已经结束-或者已经结束了?";}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: