真正的异步WCF服务

时间:2011-11-09 12:27:26

标签: c# wcf asynchronous

我正在实现异步服务。在评估了微软的example之后,我想知道他们的方法是否真的是异步的。我很确定它是,但我在网上看到的一些样本和AsyncCallback参数让我不知道。

根据示例,我们需要实现 Begin End 方法对,如下所示:

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state)
{
  // Starts synchronous task
  var acmeAsyncResult = new AcmeAsyncResult<Anvil>
  {
     Data = new Anvil()
  };      
  return acmeAsyncResult;
}

public Anvil EndGetAcmeAnvil(IAsyncResult result)
{
  var acmeAsyncResult = result as AcmeAsyncResult<Anvil>;

  return acmeAsyncResult != null
    ? acmeAsyncResult.Data
    : new Anvil();
}

非常简单,但为什么我们有一个AsyncCallback参数?我们不应该拨打callback来调用结束方法吗?

这就是我的想法:

public delegate void AsyncMethodCaller(AcmeAsyncResult<Anvil> acmeAsyncResult, 
                                       AsyncCallback callback);

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state)
{
  var acmeAsyncResult = new AcmeAsyncResult<Anvil>();
  var asyncMethodCaller = new AsyncMethodCaller(GetAnvilAsync);

  // Starts asynchronous task
  asyncMethodCaller.BeginInvoke(acmeAsyncResult, callback, null, null);

  return acmeAsyncResult;
}

private void GetAcmeAnvilAsync(AcmeAsyncResult<Anvil> acmeAsyncResult,
                               AsyncCallback callback)
{
  acmeAsyncResult.Data = new Anvil();
  callback(acmeAsyncResult);  // Triggers EndGetAcmeAnvil
}

public Anvil EndGetAcmeAnvil(IAsyncResult result)
{
  var acmeAsyncResult = result as AcmeAsyncResult<Anvil>;

  return acmeAsyncResult != null
    ? acmeAsyncResult.Data
    : new Anvil();
}

我使用loadUI进行了一些负载测试,但没有明显的性能变化。

2 个答案:

答案 0 :(得分:5)

我找到了good article,解释了如何从异步WCF服务中获得最佳性能。

要点是:

  1. 不要在开始方法和
  2. 中做大量工作
  3. 执行回调以触发结束方法。
  4. 以下是文字摘录:

    为了获得最佳性能,调用/实现上述异步模式时有以下两个原则:

    • 原则1: 不要在开始方法中执行重量级工作......

      原因是您应该尽快返回调用线程,以便调用者可以安排其他工作。如果它是UI线程,则应用程序需要使用该线程来响应用户输入。如果可能的话,你应该总是将重度操作放在不同的线程中。

    • 原则2: 避免在开始结束方法>方法。

      结束方法通常是阻止的。它等待操作完成。如果您实施结束方法,您会看到它实际上调用 IAsyncResult.WaitHandle.WaitOne()。另一方面,作为正常实现,此 WaitHandle 是分配 ManualResetEvent 的延迟。只要你不打电话,它根本就不会分配。为了快速操作,这非常便宜。但是,一旦调用结束,您就必须分配它。致电结束的正确位置来自操作的回调。当调用回调时,这意味着阻止工作确实已完成。此时,您可以调用结束来检索数据而不会牺牲性能。

答案 1 :(得分:2)

我认为这样分离的主要原因是WCF运行时正在处理线程同步,而不是必须手动处理它。

如果您通过回调调用end方法,则必须处理同步,这会使模式变得更复杂(正如您在编码示例中所看到的)。这种模式的目标不是让你真正了解线程的东西,你只想编写长时间运行的操作,而不必考虑线程的实现细节。