WCF - AsyncPattern性能性能、WCF、AsyncPattern

2023-09-06 18:58:02 作者:⒐○後ㄋ堕落

我写了下面的WCF服务而实现两个方法。他们都做同样的事情,但其中之一是同步的,另外一个异步的。负载测试的结果(使用 Pylot )令人失望。我得到的方法(见下面的性能数据)的同步和异步版本几乎相同的吞吐量。

我部署一个真正的IIS站点(不卡西尼)的服务,我看到了同样的模式。我究竟做错了什么?我下的是IM pression是使用WCF AsyncPattern我将能够增加负荷。是我的假设是否正确?难道我做错了什么?

谢谢!

  [的ServiceContract]
公共类服务1
{
    //同步版本
    [WebGet(UriTemplate =/同步)]
    公开名单< SampleItem> GetSamples()
    {
        返回this.LongRunningMethod();
    }

    //异步版本 - 开始
    [WebGet(UriTemplate =/异步)]
   [OperationContract的(AsyncPattern =真)
    公众的IAsyncResult BeginGetSampleAsync(AsyncCallback的回调,对象的状态)
    {
        VAR任务=任务<列表< SampleItem>> .Factory.StartNew(()=> this.LongRunningMethod());

        FUNC<列表< SampleItem>> getSampleItems =()=> this.LongRunningMethod();

        返回getSampleItems.BeginInvoke(回调,状态);
    }

    //异步版本 - 完
    公开名单< SampleItem> EndGetSampleAsync(IAsyncResult的结果)
    {
        AsyncResult typedAsyncResult =(AsyncResult)的结果;
        FUNC<列表< SampleItem>> FUNC =(Func键<列表< SampleItem>>)typedAsyncResult.AsyncDelegate;

        返回func.EndInvoke(结果);
    }

    私人列表< SampleItem> LongRunningMethod()
    {
        //模拟一些负载... I / O操作
        Thread.sleep代码(500);

        返回新的List< SampleItem>(){新SampleItem(){n = 1的StringValue =你好}};
    }
 

下面是PERF。数字。

 性能数据
-------------------------------------------------
测试参数:
  座席数:500
  测试时间(秒):60
  rampup以秒为单位:0
  间隔时间(毫秒):0
  测试用例XML:** syncTestCase.xml **
  日志消息:假


开始代理500

所有代理运行...


[################ 100%##################] 60/60

要求:3836
错误:0
平均响应时间:7.286
平均吞吐量:63.92
电流输出:70
接收的字节数:852036

-------------------------------------------------

测试参数:
  座席数:500
  测试时间(秒):60
  rampup以秒为单位:0
  间隔时间(毫秒):0
  测试用例XML:** asyncTestCase.xml **
  日志消息:假


开始代理500

所有代理运行...


[################ 100%##################] 60/60

要求:3884
错误:0
平均响应时间:7.176
平均吞吐量:64.6​​6
电流输出:620
接收的字节数:862248

-------------------------------------------------
 

解决方案 WCF 开发实战系列 一

您的测试是很做作。异步编程是最适合重 I / O密集​​型操作这应该不需要等待一个正在运行的线程(相反,它们应该根据的 IO-完成端口或类似)。您的测试使用线程池中的线程(的BeginInvoke / EndInvoke会),并将其块(的Thread.Sleep ),这几乎保证你最终会做的糟糕的比同步的情况下,你不吃掉任何额外的线程。

总之:不要使用服务器端异步除非你有I / O密集​​型的工作做在服务器端 - 如果你是CPU的限制,坚持同步服务器实现(可能与组合 MaxConcurrentCalls 的设定等于CPU核心在服务器上的数)。

I wrote the following WCF Service which implement two methods. They both do the same thing but one of them is synchronous, the other one asynchronous. The result of the load test (using Pylot) are disappointing. I get an almost identical throughput from the sync and async version of the method (see performance numbers below).

I deployed the service in a real IIS site (not Cassini) and I am seeing the same pattern. What am I doing wrong? I was under the impression that using the WCF AsyncPattern I would be able to increase the load. Is my assumption correct? Am I doing something wrong?

Thanks!

[ServiceContract]
public class Service1
{
    // Synchronous version
    [WebGet(UriTemplate = "/sync")]
    public List<SampleItem> GetSamples()
    {
        return this.LongRunningMethod();
    }

    // Asynchronous version - Begin
    [WebGet(UriTemplate = "/async")]
   [OperationContract(AsyncPattern = true)]
    public IAsyncResult BeginGetSampleAsync(AsyncCallback callback, object state)
    {
        var task = Task<List<SampleItem>>.Factory.StartNew(() => this.LongRunningMethod());

        Func<List<SampleItem>> getSampleItems = () => this.LongRunningMethod();

        return getSampleItems.BeginInvoke(callback, state);
    }

    // Asynchronous version - End
    public List<SampleItem> EndGetSampleAsync(IAsyncResult result)
    {
        AsyncResult typedAsyncResult = (AsyncResult)result;
        Func<List<SampleItem>> func = (Func<List<SampleItem>>)typedAsyncResult.AsyncDelegate;

        return func.EndInvoke(result);
    }

    private List<SampleItem> LongRunningMethod()
    {
        // Simulate some load... I/O operations
        Thread.Sleep(500);

        return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
    } 

Below are the perf. numbers.

Performance Numbers
-------------------------------------------------
Test parameters:
  number of agents:          500
  test duration in seconds:  60
  rampup in seconds:         0
  interval in milliseconds:  0
  test case xml:             **syncTestCase.xml**
  log messages:              False


Started agent 500

All agents running...


[################100%##################]  60s/60s

Requests:  3836
Errors: 0
Avg Response Time:  7.286
Avg Throughput:  63.92
Current Throughput:  70
Bytes Received:  852036

-------------------------------------------------   

Test parameters:
  number of agents:          500
  test duration in seconds:  60
  rampup in seconds:         0
  interval in milliseconds:  0
  test case xml:             **asyncTestCase.xml**
  log messages:              False


Started agent 500

All agents running...


[################100%##################]  60s/60s

Requests:  3884
Errors: 0
Avg Response Time:  7.176
Avg Throughput:  64.66
Current Throughput:  620
Bytes Received:  862248

-------------------------------------------------

解决方案

Your test is very artificial. Asynchronous programming is best for heavily I/O-bound operations which should not require waiting on a running thread (rather, they should be based on IO-completion ports or similar). Your test uses thread pool threads (BeginInvoke/EndInvoke) and blocks them (Thread.Sleep) which almost guarantees that you will end up doing worse than in the sync case where you don't eat up any extra threads.

In short: don't use server-side async unless you have I/O-bound work to do on the server side -- if you are CPU bound, stick to a synchronous server implementation (potentially in combination with a MaxConcurrentCalls setting equal to the number of CPU cores on the server).

 
精彩推荐