Mar*_*ell 19 .net asp.net asp.net-mvc asynchronous task-parallel-library
考虑以下(基于默认的MVC模板),这是在后台发生的一些"东西"的简化版本 - 它完成得很好,并显示预期的结果,20:
public ActionResult Index()
{
var task = SlowDouble(10);
string result;
if (task.Wait(2000))
{
result = task.Result.ToString();
}
else
{
result = "timeout";
}
ViewBag.Message = result;
return View();
}
internal static Task<long> SlowDouble(long val)
{
TaskCompletionSource<long> result = new TaskCompletionSource<long>();
ThreadPool.QueueUserWorkItem(delegate
{
Thread.Sleep(50);
result.SetResult(val * 2);
});
return result.Task;
}
Run Code Online (Sandbox Code Playgroud)
但是,现在如果我们async
在混合中添加一些:
public static async Task<long> IndirectSlowDouble(long val)
{
long result = await SlowDouble(val);
return result;
}
Run Code Online (Sandbox Code Playgroud)
并将路线中的第一行更改为:
var task = IndirectSlowDouble(10);
Run Code Online (Sandbox Code Playgroud)
然后它不起作用 ; 它反而超时了.如果我们添加断点,方法return result;
中的async
方法只在路由完成后才会发生- 基本上,看起来系统async
在请求完成之前不愿意使用任何线程来恢复操作.更糟糕的是:如果我们使用过.Wait()
(或访问过.Result
),那么它将完全陷入僵局.
那么:那是什么?最明显的解决方法是"不涉及async
",但消耗库等.当最终是不容易的,没有功能差异之间SlowDouble
和IndirectSlowDouble
(虽然有明显的结构性差异).
注意:在console / winform/etc中完全相同的东西都可以正常工作.
dav*_*owl 11
这与在ASP.NET(Pre .NET 4.5)中实现同步上下文的方式有关.关于这种行为有很多问题:
Task.WaitAll挂起了ASP.NET中的多个等待任务
Asp.net SynchronizationContext锁定HttpApplication以实现异步延续?
在ASP.NET 4.5中,有一个本文中描述的同步上下文的新实现.
http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx
当你使用时.Result
,总会有死锁的可能性,因为.Result
它本质上是阻塞的.避免死锁的方法是不阻塞任务(你应该使用async
并await
一直向下).这里的主题详细描述如下:
一个修复是添加ConfigureAwait
:
public static async Task<long> IndirectSlowDouble(long val)
{
long result = await SlowDouble(val).ConfigureAwait(false);
return result;
}
Run Code Online (Sandbox Code Playgroud)
另一个解决方法是使用async
/ await
贯穿:
public async Task<ActionResult> Index()
{
var task = IndirectSlowDouble(10);
long result = await task;
ViewBag.Message = result.ToString();
return View();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1815 次 |
最近记录: |