应该废弃 Task.Wait 吗?

5
我曾经吃过亏,从池线程调用Task.Wait可能会导致线程饥饿死锁。根据这篇MSDN文章的“死锁”章节,我们应该遵守以下两个规则:
- 不要创建任何类,其同步方法等待异步函数,因为此类可能会从池线程中调用。 - 如果该类阻塞等待异步函数,请勿在异步函数内部使用该类。
似乎Task.Wait唯一合法的使用场景就是Main函数——我有点夸张了,但你明白我的意思。既然Task.Wait如此危险,为什么它仍然是.NET框架的一部分呢?
1个回答

5
因为您想要能够同步阻塞Task。虽然很少,但您仍然需要。正如您所说,Main可能是最受欢迎(也最好是唯一)使用它的地方。此外,微软以其向后兼容性而著称,因此一旦引入了这个功能,它就不太可能被弃用或从BCL中消失。对于Task.WaitAll也是如此。

在我看来,真正的问题是当人们没有正确阅读文档并不理解调用此类方法的影响时,他们最终会误用它。如果您小心使用,它可以很好地完成工作。


另一件事是你不能总是完全使用异步。不幸的是,很多时候你有同步代码,其签名无法更改,需要调用异步方法。是的,这是危险的,也是所有人都反对的反模式的异步代码,我自己在SO上回答了至少十几个问题,其中人们最终会死锁并且不知道为什么,但TPL作者仍然需要使这些类型的调用成为可能。


2
我不同意在那种情况下人们没有正确阅读文档的说法。绝大部分文档都是误导性的,让人们相信调用Task.Wait、Task.Result或太多其他不同的方式来自毁前程并没有什么问题。 - ZunTzu
@ZunTzu 根据文档,我不仅指的是 MSDN。只需在 Google 上搜索“Task.Wait”就会出现匹配项,明确告诉您不要在异步代码上阻塞。此外,学习异步等待需要实验和阅读,有许多博客文章描述了这些死锁场景。用户有责任知道他正在使用什么以及如何使用它。我确实同意 MSDN 文档缺乏关于同步阻塞异步操作的危险性的足够信息。 - Yuval Itzchakov
文档应该更明确地说明风险,例如像Thread.Abort一样进行说明。 - ZunTzu
你发布的链接是关于Stephen Cleary解释同步上下文死锁问题的。但那篇文章也是误导性的,因为不使用同步上下文并不能使Task.Wait安全。我向你发起挑战,找一篇关于Task.Wait和线程池饥饿的文章。 - ZunTzu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接