【问题标题】:Async WCF Service异步 WCF 服务
【发布时间】:2013-05-24 23:27:22
【问题描述】:

为了更容易理解:我们使用的数据库没有内置连接池。我们正在实现自己的连接池。

好的,所以标题可能没有给出最好的描述。让我先描述一下我要做什么。我们有一个 WCF 服务(托管在 Windows 服务中),它需要能够同时接受/处理多个请求。 WCF 服务将接受请求并尝试与(例如)10 个可用的数据库连接进行通信。这些数据库连接都由 WCF 服务跟踪,并且在处理设置为忙时。如果一个请求进来并且 WCF 尝试与 10 个数据库连接之一对话并且所有这些连接都设置为忙,我们希望 WCF 服务等待并在响应可用时返回。

我们尝试了一些不同的方法。例如我们可以有 while 循环 (yuck)

[OperationContract(AsyncPattern=true)]
ExecuteProgram(string clientId, string program, string[] args)
{
    string requestId = DbManager.RegisterRequest(clientId, program, args);
    string response = null;
    while(response == null)
    {
        response = DbManager.GetResponseForRequestId(requestId);
    }

    return response;
}

基本上,DbManager 会跟踪请求和响应。每个请求都会调用 DbManager,它会分配一个请求 ID。当数据库连接可用时,它将分配(例如)Responses[requestId] = [数据库响应]。该请求会不断地询问 DbManager 是否有响应,并且当它有响应时,请求可以返回它。

这到处都有问题。我们可能有多个线程卡在 while 循环中,谁知道多长时间。这对于性能和 CPU 使用率来说是很糟糕的。 (至少可以这么说)

我们还研究过在事件/侦听器上进行尝试。我不知道这将如何实现,所以下面的代码更像是我们设想的工作方式。

[OperationContract(AsyncPattern=true)]
ExecuteProgram(string clientId, string program, string[] args)
{
    // register an event
    // listen for that event
    // when that event is called return its value
}

我们还研究了具有队列或使用诸如 Pulse/Monitor.Wait(我们不熟悉)之类的 DbManager。

所以,问题是:我们怎样才能有一个异步 WCF 操作在它能够返回时返回?

【问题讨论】:

  • 用信号量保护你的连接池。

标签: c# wcf asynchronous


【解决方案1】:

WCF 支持 .net 4.5 http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx 中的 async/await 关键字。您需要进行一些重构以使您的 ExecuteProgram 异步并使您的 DbManager 请求操作可等待。

如果您需要 DbManager 在结果可用于给定 clientId 时管理这些任务的完成,您可以将每个 clientId 映射到 TaskCompletionSourceTaskCompletionSource 可用于创建Task,DbManager 可使用TaskCompletionSource 设置结果。

【讨论】:

    【解决方案2】:

    这应该可以工作,使用正确实现的async 方法来调用:

    [OperationContract]
    string ExecuteProgram(string clientId, string program, string[] args)
    {
        Task<string> task = DbManager.DoRequestAsync(clientId, program, args);
        return task.Result;
    }
    

    您是否手动管理 10 个数据库连接?听起来您已经重新实现了数据库连接池。也许您应该使用 DB 服务器或驱动程序内置的连接池。

    【讨论】:

    • 是的,它应该可以工作,但与直接调用 return DbManager.DoRequest(....) 相比有什么优势
    • 如果 ExecuteProgram 的实现本身不遵循异步模式,则该线程将无法处理多个请求。
    • 我们实际上是在尝试实现连接池(有点)。不幸的是,我们使用的数据库不是您的普通 sql/nosql 数据库。
    • @Clamidity 那么您问题中的所有 bla bla 都是不必要的,因为连接池可以在任何代码中使用,而不仅仅是在 WCF 中。编写代码并在所有环境中使用......
    • 我们的数据库服务器/驱动程序没有内置的连接池。这就是为什么我们试图自己实现它。我们通过 telnet/ssh 连接到数据库。
    【解决方案3】:

    如果您只有一个数据库服务器(我怀疑这很可能),那么只需为您的池使用 BlockingCollection

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-03
      • 2011-05-04
      • 1970-01-01
      • 2010-12-25
      • 2012-07-16
      • 2014-11-09
      相关资源
      最近更新 更多