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

C# 避免异步在方法签名中传播,c#,.net,async-await,C#,.net,Async Await,阻止我在.net代码中不断使用async/wait模式的是,一旦创建了一个async方法,async关键字就会在代码中传播,迫使我将所有方法都设置为异步。是否有一种模式可以有效地阻止这种情况?如前所述,您应该一直保持异步 在某些情况下,我们使用litle助手类来切断异步模式。此类允许您通过替换SynchronizationContext来等待结果,而不会导致死锁 public class NoSynchronizationContextScope : IDisposable { priv

阻止我在.net代码中不断使用async/wait模式的是,一旦创建了一个async方法,async关键字就会在代码中传播,迫使我将所有方法都设置为异步。是否有一种模式可以有效地阻止这种情况?

如前所述,您应该一直保持异步
在某些情况下,我们使用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
   }
}

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

public async Task OuterFuncAsync()
{
    await Task.Run(() => InnerFunc());
}
阻止我在.net代码中不断使用async/wait模式的是,一旦创建了一个async方法,async关键字就会在代码中传播,迫使我将所有方法都设置为异步。是否有一种模式可以有效地阻止这种情况

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

也就是说,在某些情况下,部分异步的堆栈是有意义的。例如,如果您的代码库暂时处于转换状态。在这种情况下,您可以使用我的文章中描述的其中一种黑客:

  • 直接阻塞(可能导致死锁)
  • 线程池线程上的阻塞(在不同线程和不同上下文上执行代码,可能会导致意外的并行性)
  • 使用线程池上下文阻塞当前线程(在不同上下文中执行代码,可能导致意外的并行性)
  • 在具有单线程上下文的线程上阻塞(在不同线程和不同上下文上执行代码)
  • 嵌套消息循环上的阻塞(可能导致意外的重入)

所有这些都是黑客,都有不同的缺点。没有哪种破解方法适用于每种情况。

对于一种非常特殊的方法,如果您希望开始运行,但不等待结果(即触发事件处理程序),则可以使用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.)
    }
}

是的,不使用wait/async。通常它是“一路异步”。为什么不希望应用程序的一部分是异步的?void-只是不要从异步方法返回任何内容…异步应该在任何有意义的地方使用。如果您不打算做任何异步工作,为什么要将其标记为异步?没有人强迫你做任何异步的事情,只是异步任务。@JLevett它不会导致死锁,相反,调用方将无法知道操作何时完成,或者结果是什么,在完成之前,我们将继续讨论。这里有一些关于此解决方案的进一步讨论:如果您不需要同步上下文,请使用
ConfigureAwait(false)
。造成死锁的不是同步上下文,而是错误的编码,比如调用
.Wait()
.Result
完美的问题。我想说的是,大多数时候我并不真正需要异步,我只需要并发的工作线程,我总是觉得异步是实现同样结果的更有效的方法。异步是一种更有效的多线程方法吗?异步与多线程完全不同。异步就是使用更少的线程,而不是更多的线程。