避免异步在方法签名中传播

时间:2017-05-30 19:41:34

标签: c# .net async-await

阻止我不断在我的.net代码中使用异步/等待模式的原因是,一旦你创建了异步方法,async关键字就会通过我的代码传播,迫使我使所有方法都异步。是否有一种模式可以有效地阻止这种情况?

4 个答案:

答案 0 :(得分:3)

  

阻止我不断在我的.net代码中使用异步/等待模式的原因是,一旦你创建了异步方法,async关键字就会通过我的代码传播,迫使我使所有方法都异步。是否有一种模式可以有效地阻止这种情况?

让我问你这个问题,那么:你为什么要使用async / await?您需要退后一步,决定是否需要异步代码的好处。如果您确实需要这些好处,那么您的代码必须是异步的。 一旦你阻止一个线程,你就失去了异步的所有好处。所以,真的,为什么要使用异步代码,如果你还要阻止一个线程?

也就是说,在某些情况下,部分 - async堆栈是有意义的。例如,如果您的代码库在转换状态下暂时。在这种情况下,您可以使用我在brownfield async

上的文章中描述的其中一个黑客攻击
  • 直接阻止(可能导致死锁)。
  • 阻塞线程池线程(在不同的线程和不同的上下文上执行代码,可能会导致意外的并行性)。
  • 使用线程池上下文阻塞当前线程(在不同的上下文中执行代码,可能会导致意外的并行性)。
  • 使用单线程上下文阻塞线程(在不同的线程和不同的上下文上执行代码)。
  • 阻止嵌套的消息循环(可能导致意外的重入)。

所有这些都是黑客攻击,并且都有不同的缺点。在每种情况下都没有适用的黑客。

答案 1 :(得分:0)

如前所述,您应该始终保持异步...
在某些情况下,我们使用litle辅助类来切断异步模式。此类允许您通过替换SynchronizationContext来等待结果而不会导致死锁。

public class NoSynchronizationContextScope : IDisposable
{
    private readonly SynchronizationContext synchronizationContext;

    public NoSynchronizationContextScope()
    {
        synchronizationContext = SynchronizationContext.Current;
        SynchronizationContext.SetSynchronizationContext(null);
    }

    public void Dispose() => SynchronizationContext.SetSynchronizationContext(synchronizationContext);
}

void fn() 
{
   using (new NoSynchronizationContextScope())
   {
       fnAsync().Wait();
       // or 
       // var result = fnAsync().Result(); 
       // in case you have to wait for a result
   }
}

答案 2 :(得分:0)

您可以使用异步方法并在任务中调用非异步方法,因此外部方法的行为类似于异步,内部方法仍然是同步的。

public async Task OuterFuncAsync()
{
    await Task.Run(() => InnerFunc());
}

答案 3 :(得分:0)

在您想要开始运行但不等待结果(即触发事件处理程序)的方法的特定情况下,您可以使用async void。只需确保在此时捕获所有错误:

public async void DoSomething() {
    try {
        var o = await DoThing1();
        await DoThing2(o);
    } catch (Exception e) {
        // Log the error somewhere (to a file, database, etc.)
    }
}