【问题标题】:Cannot use extension command to call async from synchronous?不能使用扩展命令从同步调用异步?
【发布时间】:2020-01-20 23:05:44
【问题描述】:

我发现我们一直在代码库中使用的一种扩展方法从同步代码中调用异步方法并没有完全达到我的预期。代码遵循 MSDN 上的指南:https://docs.microsoft.com/en-us/archive/msdn-magazine/2015/july/async-programming-brownfield-async-development

public static T AsyncSafeWait<T>(this Task<T> task)
{
    T retVal = default;
    Task.Run(async () => retVal = await task).Wait();
    return retVal;
}

这允许简单直观的使用:

var response = PostAsync(...).AsyncSafeAwait();

但是,由于这是一种扩展方法,因此会启动异步调用,因此在将 Task 交给扩展方法之前会捕获当前上下文。这在许多同步情况下会导致问题,最明显的是在导致死锁的 UI 线程上。从本质上讲,扩展方法并不比 .Result 有用,出于同样的原因等等,这是一种不好的做法。

我的问题是:有什么办法可以结束这个丑陋的去异步 Task.Run 代码,这样我就不必到处复制粘贴 Task.Run(async () =&gt; retVal = await TheRealAsyncCall(...)).Wait(); 了吗?

谢谢!

【问题讨论】:

  • “这会导致许多同步情况下的问题” -- 如果没有特定 问题,问题就太宽泛了。但是,您是否尝试过在Task.Run() 委托中简单地使用await task.ConfigureAwait(false)?如果您可以改进问题,使其包含一个很好的 minimal reproducible example 来展示要解决的单个特定问题,这将有助于使其适用于 Stack Overflow。
  • 是的。用异步方法包装它,并使其他方法也异步;)

标签: c# .net asynchronous task


【解决方案1】:

有什么方法可以结束这个丑陋的去异步 Task.Run 代码

没有。任何Task 扩展方法都在Task 的单个实例上运行,并且必须已经在代码具有Task 时调用该方法。

一旦你的代码有了Task,再改变调用方法的方式就太晚了。最好的解决方案是通过委托。或者干脆彻底删除AsyncSafeWait方法,然后开始清理。

【讨论】:

  • “或者完全删除 AsyncSafeWait 方法,然后开始清理。” - 我知道你认识这个 Stephen,但我只是想向 OP 强调一点这确实是最理想的方式。人们一直在寻找这种方法并认为“微软做到了,所以它一定没问题”。但它是毒药。
  • @GabrielLuci:我不知道微软有任何AsyncSafeWait 方法有这种行为;该方法从根本上被打破。引用的文章在 Task.Run 中运行异步代码,因此基于该文章的方法应该采用委托参数,而不是 Task。但是,是的,我已经多次看到同样的问题。
  • 抱歉,我没有点击链接 :) 我以为是引用 this
猜你喜欢
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多