Task.Run()不是异步运行的
本文关键字:异步 运行 Run Task | 更新日期: 2023-09-27 17:49:42
我有一个ASP。. NET MVC 3站点连接到WCF服务。WCF服务独立于站点,并托管在Windows服务中。大多数调用都是同步的,所以等待WCF完成它的工作不是问题。
然而,其中一个(已经实现的)调用花费的时间太长了,而且,因为它本质上不直接输出任何东西,我想把它放在服务上,忘记它。
所以我把代码改成:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
,据我所知,它应该启动一个异步请求,并立即返回。然而,执行是完全同步的,UI被冻结,直到操作结束。
我错过了什么明显的东西?
更新:
另外,请注意,我不希望将服务器实现更改为异步实现,只是为了在调用站点上取消对服务的同步调用。
此外,我注意到StartSlowCalculation
方法完成执行,但服务器直到服务方法完成执行才返回响应。
WCF服务代理只是做:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
所以它是完全同步的,但这并不重要,因为它应该在一个独立的线程上执行。
任务操作可以在调用线程中运行,这取决于taskScheduler的决定。为了帮助TaskScheduler
对长时间运行的调用做出正确的决定,您可以指定任务创建选项TaskCreationOptions.LongRunning
。
你可以检查任务操作是否在一个单独的线程中运行:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
顺便说一句,您是否使用任何Task.Wait()
操作?它也会阻塞调用线程。
所以尝试使用Task.Factory.StartNew()
并指定取消令牌,即使你不需要它,听起来很奇怪,但似乎这保证任务最终不会在调用线程中运行。如果我说错了请指正
我以前这样做过。
最健壮的方法是使用异步控制器,或者最好是一个独立的服务,如WCF服务。
但根据我的经验,我只需要做"简单"的一行任务,比如审计或报告。
在这个例子中,最简单的方法——启动一个任务:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
这是一个简单的例子。你可以启动任意多的任务,同步它们,当它们完成时得到通知,等等。
详细信息请参见此链接。
https://msdn.microsoft.com/en-us/library/dd321439 (v = vs.110) . aspx