我使用Visual Studio 2012创建了一个ASP WebApplication。
如果我按如下方式修改默认页面:
public partial class _Default : Page
{
static async Task PerformSleepingTask()
{
Action action = () =>
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
int dummy = 3; // Just a nice place to put a break point
};
await Task.Run(action);
}
protected void Page_Load(object sender, EventArgs e)
{
Task performSleepingTask = PerformSleepingTask();
performSleepingTask.Wait();
}
}
在致电performSleepingTask.Wait()
时,它会无限期挂起。
<小时/> 有趣的是,如果我在web.config中设置它:
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
</appSettings>
然后它确实有效。 Wait
函数等待休眠在另一个线程上完成,然后继续。
有人可以解释一下:
TaskFriendlySynchronizationContext
的东西? (鉴于它导致任务挂起,我不会称之为“友好”)async
方法的“最佳实践”?这是我提出的一个可以实现的实现,但感觉就像笨拙的代码:
protected void Page_Load(object sender, EventArgs e)
{
ManualResetEvent mre = new ManualResetEvent(false);
Action act = () =>
{
Task performSleepingTask = PerformSleepingTask();
performSleepingTask.Wait();
mre.Set();
};
act.BeginInvoke(null, null);
mre.WaitOne(TimeSpan.FromSeconds(1.0));
}
答案 0 :(得分:4)
为什么要挂?
代表Task
的{{1}}正在尝试在其PerformSleepingTask
之后恢复,以便await
可以返回。它正在尝试重新进入ASP.NET请求上下文,该请求上下文被PerformSleepingTask
的调用阻止。 This causes a deadlock, as I expound on my blog
要避免死锁,请遵循以下最佳做法:
Wait
。请勿阻止async
代码。async
。为什么他们有
ConfigureAwait(false)
的东西? (鉴于它导致任务挂起,我不会称之为“友好”)
TaskFriendlySynchronizationContext
使用新的TaskFriendlySynchronizationContext
(.NET 4.0 AspNetSynchronizationContext
已重命名为TaskFriendlySynchronizationContext
),它还使用了新的LegacyTaskFriendlySynchronizationContext
- 知晓管道
我不是百分之百确定这个,但我怀疑原因async
适用于旧版SyncCtx的原因是旧的管道没有将SyncCtx放到位然而。我不确定为什么会以这种方式行事(除非Page_Load
是Page.Async
)。
是否有从页面处理程序方法调用异步方法的“最佳实践”?
Absolutely。您可以只创建事件处理程序false
,也可以使用async void
。第一种方法更容易,但第二种方法受到ASP.NET团队的青睐。