在任务中进行异步/等待数据库调用?

时间:2013-04-02 16:21:38

标签: c# wcf asynchronous task-parallel-library async-await

我们有一个WCF服务,它以下列方式处理传入的消息:

public bool ProcessMessage(string message)
{
    var returnValue = GetReturnValue();

    Task.Run(() => {
        //do some things with the message
        UpdateDatabase();
        SendRepliesOverNetwork();
    });

    return returnValue;
}

为了尽可能多地处理消息,我们在此处添加了任务。我们希望尽快将returnValue返回给调用者,并让Task完成它的工作。

我的问题:使用等待的异步数据库调用和/或使用异步方法通过网络进行回复是否有任何优势?

我很谨慎,因为我认为这可能会造成太多的上下文切换。我们已经看到该应用在负载下使用了100多个线程。

2 个答案:

答案 0 :(得分:7)

首先,我建议你退后一步,真的问早点回来是个好主意。你在做什么通常是危险的;在进行实际处理之前,您将“OK”返回给客户端。如果您的客户知道“returnValue”并不意味着该操作已完成且仅在收​​到“SendReplies”时认为它已完成,那么这只是一个好主意。

那就是说,是的,你应该看到一些好处,你可以做一切异步。如果您的所有任务都是非阻塞的,那么您将更好地利用线程池(减少上下文切换)。

public bool ProcessMessage(string message)
{
  var returnValue = GetReturnValue();

  Task.Run(async () => {
    //do some things with the message
    await UpdateDatabaseAsync();
    await SendRepliesOverNetworkAsync();
  });

  return returnValue;
}

答案 1 :(得分:4)

我可以看到这种方法存在一些潜在的问题。

首先,如果你在IIS中托管你的WCF服务,那么使用比请求更长的后台线程是一个很大的禁忌。当请求完成后,IIS可以自由拆除整个AppDomain,这会以极端的偏见中止所有后台工作!

其次,如果现有工作正在增加,WCF将限制请求。使用此模式,您可以快速处理请求,并且可以无限制地增加为线程池排队的工作量。


您可以尝试使用WCF异步服务方法。这将释放只等待IO的线程 - 您的数据库和网络访问 - 这可以提高吞吐量。

这里有一篇关于这种方法的深入文章:Dan Rigsby: Async Operations in WCF

此外,MSDN中有一节:WCF: Synchronous and Asynchronous Operations