我有一个WCF Rest服务,它公开一个Web方法,该方法应该从一个长时间运行的进程开始,然后立即返回一个id,表示可用于跟踪任务状态的任务。
[WebGet]
public Task<Guid> LongRunningProcess()
{
var taskId = new Guid();
var task = Task.Factory.StartNew(() =>
{
//Perform long running task
}
task.ContinueWith(task =>
{
//Send a notification to the client that the task has completed.
}
return taskId;
}
我的问题是,这是正确的方法吗?还是有更好更轻量级的方法?
答案 0 :(得分:0)
你在那里描绘的是(通过微小的修正)一种方法来实现你想要做的事情。更难的部分是客户通知(我们成功使用SignalR集线器,但确切的机制取决于您)。
我谈到的一个小修正是,您的方法的返回类型应该只是上面代码中的Guid
。
一些说明: 在性能方面,TPL可以很好地扩展(IMO),但在更大规模上,您可能希望能够在多个服务器上分发长时间运行的任务等......
对于这种情况,我建议您查看分发作业队列(例如Resque,存在.NET端口),它们非常适合这种用例。
答案 1 :(得分:0)
我的理解是,如果你的工作受CPU限制,你最好同步执行工作。使用您的方法,请求将被停放并且原始请求线程将被释放,但随后将工作交给另一个线程,并且在该线程完成之前请求不会完成。你也可以在原始主题中完成工作。
如果你有一些IO,那么异步IO不会使用一个线程就会有意义,它可以释放你的请求线程来处理其他请求,从而提高你的可伸缩性。
更新
我认为您采用的方法很好,但鉴于您使用的是.NET 4.5,我会使用async-await
,因为它会产生更简单的代码。然后我将使用IO操作的异步API和await
其结果。例如:
[WebGet]
public async Task<Guid> LongRunningProcess()
{
var taskId = new Guid();
// IO bound operation
var dbResult = await readFromDbAsync();
// IO bound operation
var dbResult = await readFromDbAsync();
// CPU bound?
generateReport(dbResult);
// IO bound operation
await sendNotification();
return taskId;
}
如果您不熟悉async-await
,我已为其撰写了一篇介绍here。