2013-04-02 60 views
2

我们有一个以下列方式处理传入消息的WCF服务:在任务中进行异步/等待数据库调用?

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

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

    return returnValue; 
} 

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

我的问题:使用等待异步数据库调用和/或使用异步方法进行网络回复有什么优势吗?

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

+0

这真的取决于你的应用程序的情况下,你要立即进行发送数据库更新后UI响应,还是你想要做的性能考虑? –

+0

我不认为你在等待任何东西:你在ThreadPool上排队工作并立即返回给调用者。 –

+0

@KyleC:表现。试图尽可能快地处理尽可能多的消息。 – jeremywho

回答

7

首先,我建议你退后一步,确实询问早点回来是否是一个好主意。你在做什么通常是危险的;在进行实际处理之前,您将“确定”返回给客户端。如果您的客户知道“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; 
} 
+0

returnValue基本上是一个应用程序级别,用于告诉调用者我们收到了它的消息。因此,在通话寿命之外进行处理是很好的。我会继续尝试异步数据库/网络调用。 – jeremywho

4

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

首先,如果您在IIS中托管WCF服务,则使用比请求长的后台线程是一个很大的禁忌。当请求完成时,IIS可以自由拆除整个AppDomain,这将以极端偏见中止所有后台工作!其次,如果现有工作正在进行,WCF将限制请求。使用这种模式,您可以快速处理请求,并且可以毫无限制地增加为线程池排队的工作量。


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

有一个深入的文章对这种做法在这里:Dan Rigsby: Async Operations in WCF

此外,还有在MSDN这里部分:WCF: Synchronous and Asynchronous Operations

+0

wcf服务是自我托管的,所以我认为它应该没问题。我会研究一下wcf的异步方法。 – jeremywho

+0

由于该服务是自托管的,因此它现在变成了*你的*问题而不是IIS'。考虑应用关键服务器操作系统安全更新的计划;你需要一种方法来告诉wcf服务不忙。 –