在Task中执行Async/Await db调用

本文关键字:Await db 调用 Async Task 执行 | 更新日期: 2023-09-27 18:07:10

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

public bool ProcessMessage(string message)
{
    var returnValue = GetReturnValue();
    Task.Run(() => {
        //do some things with the message
        UpdateDatabase();
        SendRepliesOverNetwork();
    });
    return returnValue;
}

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

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

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

在Task中执行Async/Await db调用

首先,我建议你退后一步,认真地问自己提前回来是否是个好主意。你所做的通常是危险的;在进行实际处理之前,您将向客户端返回"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;
}

我可以看到这种方法有几个潜在的问题。

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

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


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

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

同样,在MSDN中也有一个区域WCF: Synchronous and Asynchronous Operations