Andrei Rînea
Andrei Rînea

Reputation: 20800

WCF performance vs simple ASP.NET HttpHandler

TL;DR ver : WCF service behaves (although it seems configured for max throughput on HTTP) 4x slower than a naive ASP.NET handler implementation


UPDATE1 :

Switching to release mode and IIS (full not express) 7.5 changed numbers :


Long explanation :

I was looking for an efficient way to transfer information fast in an intranet between two different physical machines (Named pipes gets out of question). My communication contract is composed of the following operations :

void SetUserAsState1(int id);
void SetUserAsState2(int id);
byte GetUserState(int id);

Pretty simple I'd say. I won't take into consideration security, reliability etc. Just sheer performance. And by performance I mean how many req/sec can be sent to the other machine.

I've done tests on my laptop on two scenarios :

How did I test? I set up 10 threads and each thread would do 1000 requests to the target and measure the time taken to complete all 10x1000=10,000 requests.

Results?

Test harness : (no, it's not production quality)

class Program
{
    private static Service1Client _wcfProxy;

    static void Main()
    {
        _wcfProxy = new Service1Client();
        _wcfProxy.GetData(); // warm up proxy and service
        _wcfProxy.GetData(); // make it really warm :P

        var threads = new Thread[10];
        for (var cnt = 0; cnt < 10; cnt++)
        {
            //var t = new ThreadStart(TestAspnetHandler); // scenario 1
            var t = new ThreadStart(TestWcfService); // scenario 2
            (threads[cnt] = new Thread(t)).Start();
        }
        var sw = Stopwatch.StartNew();
        foreach (var thread in threads)
        {
            thread.Join();
        }
        sw.Stop();
        Console.WriteLine("Done 10 x 1000 calls in " + sw.Elapsed);
        Console.ReadLine();
    }

    private static void TestAspnetHandler()
    {
        var webClient = new WebClient();
        for (var i = 0; i < 1000; i++)
        {
            webClient.DownloadData("http://localhost:1970/GetData.ashx?id=1");
        }
    }

    private static void TestWcfService()
    {
        for (var i = 0; i < 1000; i++)
        {
            _wcfProxy.GetData();
        }
    }
}

ASP.NET implementation :

public class GetData : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        var id = context.Request.QueryString["id"];
        if (string.IsNullOrEmpty(id))
        {
            context.Response.Write("Hello World");
        }
        else
        {
            var identifier = int.Parse(id);
            context.Response.Write(identifier * 23);
        }
    }

    public bool IsReusable { get { return true; } }
}

default 4.0 configuration, no changes


WCF contract :

[ServiceContract]
public interface IService1
{
    [OperationContract]
    int GetData();
}

and implementation

[ServiceBehavior(
    ConcurrencyMode = ConcurrencyMode.Multiple, 
    InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
    public int GetData()
    {
        return 23;
    }
}

and configuration :

<services>
  <service behaviorConfiguration="beh" name="IService1">
    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttp" 
              contract="WcfService1.IService1" />
  </service>
</services>

<bindings>
  <basicHttpBinding>
    <binding name="basicHttp" allowCookies="false" />
  </basicHttpBinding>
</bindings>

<behaviors>
  <serviceBehaviors>
    <behavior name="beh">
      <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" />
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />


I've set the concurency mode to multiple (so they're not sync'ed), single service instantiation, throttling set to high values, dunno if/how can I speed up anymore the WCF service. Is there any change the WCF service will catch up to the ASP.NET one (implemented over HTTP, that is)?

Upvotes: 2

Views: 3371

Answers (1)

DaeMoohn
DaeMoohn

Reputation: 1097

Tcp gets out of the question? You can milk more performance from serialization - try NetDataContractSerialization or protobuf.net. You can cache the channel factory - so no add service reference.

Upvotes: 1

Related Questions