调用异步方法同步进行

3
我因为无法控制的原因,需要同步调用一个异步方法。我正在开发一个库,它使用另一个异步工作的库,并且我需要在Stream类的实现中使用它。这个类包含同步和异步方法,我对同步方法感到不安:
public override sealed int Read(byte[] buffer, int offset, int count)
{ 
    // potential deadlock on single threaded synchronization context
    return ReadAsync(buffer, offset, count).Result;
}

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
   return await _lib.ReadAsync(buffer,offset,count);
}

我一直在阅读如何同步运行异步Task<T>方法?,特别是这个答案,在评论中@Stephen Cleary指出解决方案并不好,因为某些ASP.NET部分期望AspNetSynchronizationContext。 我正在开发一个库,因此我不知道我的类将从哪里调用。

什么是最安全的同步调用异步方法的方法?

1个回答

3

斯蒂芬·托布在他的博客中涵盖了所有不同的方法及其相应的缺点。

只有两种通用解决方案,但都并非理想:

  1. 在您的层中复制逻辑;让您的同步方法调用库中的同步方法。(这假设库中也有同步方法和异步方法。)
  2. 阻塞返回的任务,类似于您的示例代码。这假定库始终使用ConfigureAwait(false),这是您无法控制的假设。如果库是无上下文的,则将异步调用抛入Task.Run并阻塞该任务可能更安全。此外,请确保在阻塞任务时取消包装异常,因为WaitResult会将异常包装在一个AggregateException中。

这两种解决方案都存在严重的维护问题。


我有什么遗漏吗?Task<T>.Wait将会阻塞,无论继续策略如何。 - Gusdor
2
@Gusdor:像这样阻塞是导致死锁的简单方法,正如我在博客中所解释的那样。 - Stephen Cleary
太好了!我漏掉了什么。感谢您的解释。 - Gusdor
似乎第一个方案是唯一合理且安全的解决方案。Task.Run方法是一个好的临时解决方案,直到我安排时间编写同步方法。 - vtortola
1
@vtortola:通常我建议使用第一个,但两个都不是理想的选择。 - Stephen Cleary

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