【问题标题】:How to safely mix sync and async code? [duplicate]如何安全地混合同步和异步代码? [复制]
【发布时间】:2014-06-18 22:59:33
【问题描述】:

我有这个纯粹同步的库。它公开了同步方法,我有客户使用它。

我将底层实现更改为异步,并为想要使用它的人公开了异步方法。但是现在我有很多重复的代码。异步代码似乎表现更好。我希望现有客户能够利用它,并且我想消除代码重复。

是否有任何安全的方法来保持同步签名并调用异步实现?

我特别害怕调用 .Result 和 .Wait 时出现死锁。

【问题讨论】:

  • 你真的应该这样做,如果你这样做,你最终会降低同步性能。最好的方法是对同步 API 调用使用完全同步路径,对异步调用使用完全异步路径。沿着路径重构不依赖同步或异步的代码,并让两条路径都调用函数。

标签: c# .net asynchronous async-await deadlock


【解决方案1】:

我强烈建议您不要这样做

首先,阅读 Stephan Toub 的 Should I expose synchronous wrappers for asynchronous methods?Should I expose asynchronous wrappers for synchronous methods?

我不会这样做的主要原因:

  1. 通过异步同步 - 正如您所说,死锁。在调用链的上层或下层,使用 ResultWait 处理异步可能有风险的业务。这实际上取决于您运行的平台(ASP.NET、UI、控制台),因为每个平台的行为都有些不同(即使使用 ConfigureAwait(false)

  2. 异步优于同步 - 可扩展性。一旦我看到一个异步端点,我就认为它是纯异步的,这对我来说,作为 API 的使用者意味着没有任何线程在“我背后”旋转。如果您的用户假设相同,则发现每次调用异步方法时都会使用线程池线程,这会在尝试横向扩展时严重损害性能。如果用户想用 Task.Run 包装同步方法,让他们自己来调用,并自行判断这将如何影响他们的应用程序

【讨论】:

  • 听起来 C# 异步功能是半生不熟,IMO。没有“采用”策略。并且说“重复...”不是答案。
  • C# 异步功能非常成熟,IMO。你是对的,没有“简单的出路”,但这是一个设计决定,不会让它变得不那么“成熟”。您的代码库需要适应异步。
  • “半生不熟”是指采用方面。采用策略是生态系统发展的关键:社区越小,没有人使用其功能、捕获错误等的机会就越大。
  • @Gatis,我明白了。我认为采用者的数量相当广泛 TBH。如果只是关于异步等待的 SO 问题的数量。
  • 您说任何一种方式都不是一个选项,但您从未指定何时必须这样做的选项。假设您有一个异步和同步类需要遵守的合同,您将采用哪种方式来履行该合同,同步还是异步?
【解决方案2】:

尝试从下往上开始,否则会陷入死锁(

就死锁处理方式而言,如果处理不当,控制台应用的行为与 Web 和 UI 应用不同。如果您使用的是 MVC,请使用异步任务 ActionResult 并使用 async 和 await 在 Task.Run(() => SYNCCODE) 上包装特定的同步调用。与 UI 代码类似的过程,在事件方法(例如 Click 事件处理程序)上使用 async/await。

我通常用异步版本包装我的同步调用,并将它们作为任务处理。如果这些同步方法可以利用 .NET 方法的异步版本,我会尝试尽可能“深入”。

【讨论】:

  • 我一直在做同样的事情......异步 IO 方法实际上似乎提供了一点性能提升,但不知道为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多