我有一个连接到WCF服务的ASP.NET MVC 3站点。 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);
}
因此它完全同步,但这应该无关紧要,因为它应该在一个独立的线程上执行。
答案 0 :(得分:2)
任务操作可以在调用线程中运行,它取决于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()
任何类型的操作吗?它也会阻塞调用线程。
编辑:
您可能会发现以下有趣的帖子Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
因此尝试使用Task.Factory.StartNew()
并指定取消令牌,即使您不需要它,听起来很奇怪但似乎这保证了任务最终不会在调用线程中运行。纠正我如果我错了。
答案 1 :(得分:0)
我以前做过这个。
最强大的方法是使用异步控制器,或者更好的是一个独立的服务,例如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