WCF休息服务中的后台工作

时间:2015-02-27 06:06:10

标签: c# wcf rest asynchronous task

我有一个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;
}

我的问题是,这是正确的方法吗?还是有更好更轻量级的方法?

2 个答案:

答案 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