WCF - IsOneWay 和异步的区别

在某些博客文章里,直接将 IsOneWay 称为 "异步方法"。虽然多数时候不会对开发带来什么问题,但深究起来,这两者是不同的。接下来,我们做个试验。将同一个服务契约分别用 IsOneWay 和异步进行实现,客户端使用多线程模拟并发调用,并使用 ServiceThrottlingBehavior (也可以使用 InstanceContextMode.Single) 进行并发控制。注意对比输出结果,我们就会发现其不同之处。

IsOneWay版本

[ServiceContract]
public interface IService
{
  [OperationContract(IsOneWay=true)]
  void Test();
}

public class MyService : IService
{
  public void Test()
  {
    Console.WriteLine("Service BeginAdd:{0}", DateTime.Now);
    Thread.Sleep(5000);
    Console.WriteLine("Service EndAdd:{0}", DateTime.Now);
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(MyService));
      host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://localhost:8080/myservice");

      ServiceThrottlingBehavior throttling = new ServiceThrottlingBehavior();
      throttling.MaxConcurrentInstances = 1;
      host.Description.Behaviors.Add(throttling);

      host.Open();
    });

    for (int i = 0; i < 3; i++)
    {
      new Thread(delegate()
      {
        IService channel = ChannelFactory.CreateChannel(new WSHttpBinding(),
         new EndpointAddress("http://localhost:8080/myservice"));

        using (channel as IDisposable)
        {
          Console.WriteLine("Client {0} BeginAdd:{1}",
            Thread.CurrentThread.ManagedThreadId, DateTime.Now);

          channel.Test();

          Console.WriteLine("Client {0} BeginAdd End:{1}",
            Thread.CurrentThread.ManagedThreadId, DateTime.Now);
        }
      }).Start();
    }
  }
}


输出:
Client 15 BeginAdd:2007-4-19 10:51:39
Client 14 BeginAdd:2007-4-19 10:51:39
Client 16 BeginAdd:2007-4-19 10:51:39
Client 16 BeginAdd End:2007-4-19 10:51:40
Service BeginAdd:2007-4-19 10:51:40
Service EndAdd:2007-4-19 10:51:45

Client 14 BeginAdd End:2007-4-19 10:51:46
Service BeginAdd:2007-4-19 10:51:46
Service EndAdd:2007-4-19 10:51:51
Service BeginAdd:2007-4-19 10:51:51

Client 15 BeginAdd End:2007-4-19 10:51:51
Service EndAdd:2007-4-19 10:51:56

异步版本

[ServiceContract]
public interface IService
{
  [OperationContract]
  void Test();

  [OperationContract(AsyncPattern = true)]
  IAsyncResult BeginTest(AsyncCallback callBack, object state);

  void EndTest(IAsyncResult ar);
}

public class MyService : IService
{
  public void Test()
  {
    Console.WriteLine("Service BeginAdd:{0}", DateTime.Now);
    Thread.Sleep(5000);
    Console.WriteLine("Service EndAdd:{0}", DateTime.Now);
  }

  public IAsyncResult BeginTest(AsyncCallback callBack, object state)
  {
    throw new Exception("The method or operation is not implemented.");
  }

  public void EndTest(IAsyncResult ar)
  {
    throw new Exception("The method or operation is not implemented.");
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(MyService));
      host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://localhost:8080/myservice");

      ServiceThrottlingBehavior throttling = new ServiceThrottlingBehavior();
      throttling.MaxConcurrentInstances = 1;
      host.Description.Behaviors.Add(throttling);

      host.Open();
    });

    for (int i = 0; i < 3; i++)
    {
      new Thread(delegate()
      {
        IService channel = ChannelFactory.CreateChannel(new WSHttpBinding(),
         new EndpointAddress("http://localhost:8080/myservice"));

        using (channel as IDisposable)
        {
          Console.WriteLine("Client {0} BeginAdd:{1}",
            Thread.CurrentThread.ManagedThreadId, DateTime.Now);

          IAsyncResult ar = channel.BeginTest(null, null);

          Console.WriteLine("Client {0} BeginAdd End:{1}",
            Thread.CurrentThread.ManagedThreadId, DateTime.Now);

          channel.EndTest(ar);
        }
      }).Start();
    }
  }
}


输出:
Client 14 BeginAdd:2007-4-19 10:53:56
Client 16 BeginAdd:2007-4-19 10:53:56
Client 15 BeginAdd:2007-4-19 10:53:56
Client 16 BeginAdd End:2007-4-19 10:53:56
Client 14 BeginAdd End:2007-4-19 10:53:56
Client 15 BeginAdd End:2007-4-19 10:53:56
Service BeginAdd:2007-4-19 10:53:59
Service EndAdd:2007-4-19 10:54:04
Service BeginAdd:2007-4-19 10:54:04
Service EndAdd:2007-4-19 10:54:09
Service BeginAdd:2007-4-19 10:54:09
Service EndAdd:2007-4-19 10:54:14


通 过对比,我们发现异步方法 BeginXXX 调用并不受并发控制影响,调用后直接返回控制权;而 IsOneWay 则不同,它被阻塞直到服务方法获得执行才会返回(当然,没有等待服务方法执行完成)。这点区别在处理并发性能上,可能带来不同的效果,了解 IsOneWay 和异步的差别能让我们避免一些意外的问题。

你可能感兴趣的:(WCF学习笔记)