在ASP.NET WebApi 2(不是ASP.NET Core)的上下文中询问此问题。我已经尝试过对此主题进行自己的研究,但是我找不到明确的答案。
ConfigureAwait(...)
方法参数的官方MSDN documentation指出:
true
尝试将继续情况编组回捕获的原始上下文;否则为false
。
Stephen Toub进一步解释了attempt
关键字,如下所示:
这意味着可能没有什么要整理的……可能没有要捕获的上下文,例如
SynchronizationContext.Current
可能返回null
。
如果我对它的理解正确,那么ASP.NET WebApi 2则不是这种情况,因为存在AspNetSynchronizationContext
,对吗?
现在让我们看看以下控制器动作方法:
[HttpGet]
public async Task<String> GetValues()
{
// First half.
var values = await HeavyIo().ConfigureAwait(false);
// Second half.
return values;
}
通过传递continueOnCapturedContext: false
是否可以确保标记为// Second half.
的延续在其他线程上始终得到始终执行?还是有可能如果在异步操作完成后捕获同步上下文的线程是空闲的,然后延续将在同一线程上运行?
答案 0 :(得分:4)
当我以类似否定的形式问到答案时,我认为这很清楚-无法保证下半部分将在与上半部分不同的线程上执行。正如您推测的那样,当继续执行时,原始线程很可能是幸运的,即将被选中的可用线程。
还要注意的是,还原的是上下文,不一定是 thread 。在Windows消息循环的情况下(例如WinForms UI线程),运行消息循环的UI线程将拾取并执行继续操作,因此使用ConfigureAwait(true)
可以确保使用同一线程。但是,对于其他SynchronizationContext,可能没有特别的理由要求或什至更喜欢原始线程,只要它们认为是“上下文”的内容得以恢复即可。例如HttpContext.Current
[,身份,文化]。
HeavyIo()
至少有一个理论上的同步机会,在这种情况下,无论如何都不会进行上下文切换,并且后半部分将继续与前半部分在同一线程上继续。我只能从您的命名选择(“繁重”)中假设您暗示这不是一个选择。
答案 1 :(得分:0)
在您的示例中,不保证它会在不同的线程上运行,因为这取决于 HeavyIO 的作用。
如果 HeavyIO 这样做,那么它会保证“后半部分”总是一个不同的线程。
private async Task<string> HeavyIo1()
{
string test = "";
await Task.Run(() =>
{
//Call some syncronous library thats very slow
}).ConfigureAwait(false);
return test;
}
例如,如果HeavyIO 在日期> 2011 年执行以下操作,它将在与“上半年”相同的线程上返回。如果日期在 2011 年之前,它将在不同的线程中返回。
private async Task<string> HeavyIo2()
{
if (DateTime.Now > new DateTime(2011, 1, 1)) return null;
string test = "";
await Task.Run(() =>
{
//Call some syncronous library thats very slow
}).ConfigureAwait(false);
return test;
}