不等待时ConfigureAwait

时间:2014-03-18 15:00:35

标签: c# asp.net async-await synchronizationcontext azure-webjobs

我使用了async方法来卸载几秒钟'值得一劳永逸的工作,以免减慢我的页面负载。这项工作需要一些整体设置和整理;我希望(快速)设置在抛出时同步抛出,但我不想强制整理在ASP上下文中运行,所以我在我正在等待的位上使用ConfigureAwait

public Task FireAndForget()
{
    DoSetup();
    return FireAndForgetAfterSetup();
}

private async Task FireAndForgetAfterSetup()
{
    await AFewSecondsWorthOfWork().ConfigureAwait(false);
    DoTidyUp();
}

protected void btn_Click(object sender, EventArgs e)
{
    FireAndForget();
}

这看起来很奇怪,因为

  • FireAndForgetAfterSetup不应该关心是否从ASP上下文调用它,那么为什么要调用ConfigureAwait呢?
  • 如果我改变主意并决定btn_Click应该等待FireAndForget完成,是否已经抛弃了ASP上下文(?)

如果我有误解,有人可以向我解释一下吗?

3 个答案:

答案 0 :(得分:3)

ASP.NET同步上下文不允许在请求中启动“即发即忘”工作项。运行时会主动监视这些事情并尝试生成异常,因为这些代码模式会导致null refs,死锁,AV和其他恶意。

如果您绝对需要在ASP.NET中启动“即发即弃”工作,请考虑使用WebBackgrounder。它集成了ASP.NET扩展点,旨在实现此目的。所以它不会阻止有效请求,但要记住斯蒂芬的警告:它并不能保证在所有中执行。如果您需要保证执行,请考虑像Service Bus这样的可靠性机制。

答案 1 :(得分:1)

如果您的方案是如何在加载期间执行某些(相对)长时间运行的任务,则ASP.NET允许此方案通过Page.RegisterAsyncTask方法。 Scott Hansleman描述了如何在The Magic of using Asynchronous Methods in ASP.NET 4.5 plus an important gotcha

中使用它

基本上,您创建一个返回Task并调用的异步方法:

RegisterAsyncTask(new PageAsyncTask(MyAsyncMethod));

然后调用Page.ExecuteRegisteredAsyncTasks开始执行所有已注册的任务。

Scott Hanselman(当然)做了很好的描述为什么使用事件处理程序,任务或后台线程是一个坏主意。

“异步页面事件”部分的“What Not to do in ASP.NET, What to do instead”中也对此进行了描述

答案 2 :(得分:0)

我不确定为什么他没有发布,但我的确切的两个问题在this blog post by Stephen Cleary得到解答:

  

这个例子需要注意的重点是每个"等级"异步方法调用有自己的上下文。 DownloadFileButton_Click在UI上下文中启动,并称为DownloadFileAsync。 DownloadFileAsync也在UI上下文中启动,但随后通过调用ConfigureAwait(false)退出其上下文。 DownloadFileAsync的其余部分在线程池上下文中运行。但是,当DownloadFileAsync完成并且DownloadFileButton_Click恢复时,它会在UI上下文中恢复。

     

一个好的经验法则是使用ConfigureAwait(false),除非你知道你确实需要上下文。

  • 回答我的第一个要点,是的,可以(鼓励!)在库方法中使用ConfigureAwait(false)知道他们不会使用上下文,因为... < / LI>
  • ...在回答我的第二个要点时,即使库async方法抛弃了UI上下文,调用方法仍然有自己的副本。因此调用方法可以await库方法并在UI上下文中恢复......但是当发生这种情况时它会发生死锁。