WCF Rest 服务中的后台工作
Background work in WCF Rest Service
我有一个 WCF Rest 服务公开了一个 Web 方法,该方法应该启动一个长 运行 进程,然后立即 return 一个表示可用于跟踪状态的任务的 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;
}
我的问题是,这是正确的做法吗?还是有更好更轻量级的方法?
您所勾勒的内容(稍作修改)是实现您想要做的事情的方法。更难的部分是客户端的通知(我们使用 SignalR hubs 成功地做到了这一点,但具体的机制取决于你)。
我所说的小修正是你的方法的 return 类型在上面的代码中应该只是 Guid
。
一些注意事项:
在性能方面,TPL 可以很好地扩展(IMO),但在更大的范围内,您可能希望能够将 运行 长的任务分配到多个服务器等...
对于这种情况,我建议您查看非常适合此类用例的分布式作业队列(例如 Resque,存在 .NET 端口)。
我的理解是,如果你的工作是 CPU 绑定的,你最好同步执行工作。使用您的方法,请求将被停放并且原始请求线程将被释放,但随后将工作移交给另一个线程,并且在该线程完成之前请求不会完成。您不妨在原帖中完成工作。
如果你在那里有一些 IO,那么使异步 IO 不使用线程是有意义的,它会释放你的请求线程来处理其他请求,从而提高你的可伸缩性。
更新
我认为您采用的方法很好,但考虑到您使用的是 .NET 4.5,我会使用 async-await
,因为它会产生更简单的代码。然后我会使用异步 API IO 操作和 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。
我有一个 WCF Rest 服务公开了一个 Web 方法,该方法应该启动一个长 运行 进程,然后立即 return 一个表示可用于跟踪状态的任务的 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;
}
我的问题是,这是正确的做法吗?还是有更好更轻量级的方法?
您所勾勒的内容(稍作修改)是实现您想要做的事情的方法。更难的部分是客户端的通知(我们使用 SignalR hubs 成功地做到了这一点,但具体的机制取决于你)。
我所说的小修正是你的方法的 return 类型在上面的代码中应该只是 Guid
。
一些注意事项: 在性能方面,TPL 可以很好地扩展(IMO),但在更大的范围内,您可能希望能够将 运行 长的任务分配到多个服务器等...
对于这种情况,我建议您查看非常适合此类用例的分布式作业队列(例如 Resque,存在 .NET 端口)。
我的理解是,如果你的工作是 CPU 绑定的,你最好同步执行工作。使用您的方法,请求将被停放并且原始请求线程将被释放,但随后将工作移交给另一个线程,并且在该线程完成之前请求不会完成。您不妨在原帖中完成工作。
如果你在那里有一些 IO,那么使异步 IO 不使用线程是有意义的,它会释放你的请求线程来处理其他请求,从而提高你的可伸缩性。
更新
我认为您采用的方法很好,但考虑到您使用的是 .NET 4.5,我会使用 async-await
,因为它会产生更简单的代码。然后我会使用异步 API IO 操作和 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。