默认情况下,当您使用async/await时,它将在开始请求的原始线程上继续运行(状态机)。

但是,如果当前另一个长时间运行的进程已经接管了该线程,那么你就不得不等待它完成。要避免这个问题,可以使用ConfigureAwait的方法和false参数。当你用这个方法的时候,这将告诉Task它可以在任何可用的线程上恢复自己继续运行,而不是等待最初创建它的线程。这将加快响应速度并避免许多死锁。

但是,这里有一点点损失。当您在另一个线程上继续时,线程同步上下文将丢失,因为状态机改变。这里最大的损失是你会失去归属于线程的Culture和Language,其中包含了国家语言时区信息,以及来自原始线程的HttpContext.Current之类的信息,因此,如果您不需要以此来做多语系或操作任何HttpContext类型设置,则可以安全地进行此方法的调用。注意:如果需要language/culture,可以始终在await之前存储当前相关状态值,然后在await新线程之后重新应用它。

注意事项

如果有同步方法调用异步方法,则必须使用ConfigureAwait(false)。如果不这样做,就会立即掉进死锁陷阱。

发生的情况是主线程将调用async方法,最终会阻塞这个线程,直到那个async方法完成。然而,一旦异步方法完成,它必须等待原始调用者完成后才能继续。他们都在等待对方完成,而且永远不会。通过在调用中使用configurewait (false), async方法将能够在另一个线程上完成自己操作,而不关心自己的状态机的位置,并通知原始线程它已经完成。

死锁举例

 public class HomeController : Controller
    {
        public  ActionResult Index()
        {
             DoAsync().Wait();//同步调用1,发生死锁
             //var r = DoAsync().Result;//同步调用2,发生死锁
             return View();
        }
 
        public async Task<int> DoAsync()
        {
            await Task.Delay(2000).ConfigureAwait(true);//默认就是ture
            return 1;
        }
    }
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-11-28
  • 2021-07-17
  • 2021-12-25
猜你喜欢
  • 2022-02-21
  • 2022-02-05
  • 2021-05-26
  • 2022-02-27
  • 2022-12-23
相关资源
相似解决方案