简体   繁体   中英

WCF C# slow performance of a locally hosted service

I created a WCF service; a simple getData(i). I hosted it in a windows service; wrote a client to access that service. getData(i) is "empty" - it just returns "you entered i".

Client

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();

        ServiceReference1.iRateCacheClient client = new
               ServiceReference1.iRateCacheClient();
        string returnString;
        for(int i = 0; i < 1000; i++)
            returnString = client.GetData(i);
        stopWatch.Stop();
    }
}

In that client it takes

  • ~ 2 seconds for 1 call to getData(i)
  • ~ 2.4 seconds for 100 calls
  • ~ 8 seconds for 1000 calls

Makes me think that the first call is taking too much time. My use case is that a lot of short lived client programs would be calling that service, once each. The whole purpose of writing that WCF service was that I wanted to separate out the function call from those clients to a separate process; ie I did not want to put that getData() inside of a dll that clients call.

2 seconds "overhead" for a service call is unacceptable. Am I doing something wrong? I expected that service call to be over in < 1 millisecond. I am accustomed to COM/DCOM; and the overhead for those was very minimal.

The local service is using HTTP transport.

If only the first call is so slow, you need to check whether it is the server that takes the time to start or the client. It is not unusual that the first call to a web service is slow, especially if IIS has to start the application pool etc.

So possible countermeasures are:

  • Keep the service up and running and don't let the application pool go to sleep after a short amount of time.
  • Also, you can use a more efficient transport protocol , eg Named Pipes for a service that is hosted on the same machine as the client or NetTcpBinding if the service is hosted on another machine and you do not need to interoperate with non-.NET-clients. Of course, the more data you need to transfer to and from the service, the greater the effect of a more efficient protocol will be. See this answer for an example on how to use NetNamedPipeBinding.
  • WCF is optimized for SOAP services; the SOAP protocol carries some overhead, especially if you need to transfer binary data because they need to be encoded as strings. You can also change to a REST service ; for that purpose, have a look at ASP.NET Web API as the WCF implementation is much harder to implement.
  • Reduce the amount of roundtrips to the server as much as you can.
  • Another proprietary and by that more efficient alternative to using WCF is .NET remoting , though this technology is not used widely anymore. From my personal experience, I'd favor WCF/ASP.NET Web API over this as it is supported much better both in development and infrastructure.

When judging performance, I'd not set too much weight on the first request. In addition, it is more about "is my approach fast enough" than about "is my approach faster than n ms". WCF is not an exotic technology; there are lots of systems that run fast enough on it.

Nevertheless, it is a technology built for interoperation; COM/DCOM were not built for interoperation and therefore can easily offer a better performance. Especially COM is not a good comparison as it runs in the same process; DCOM still uses a proprietary protocol. WCF always means that you have to transfer data to another process that is located on the same or another computer. This includes that you need to serialize the data into XML, transmit the data and deserialize it again. So there always is an overhead. One of the most efficient countermeasures is to reduce the number of requests to the server.

First call to WCF service is always slow.

Even more it can be also slow after some idle time (see my answer how to prevent it). But for the first call the only way to handle that is to warm up the service somehow. For example make any call during application initialization and then keep the service and thead pool alive.

To make it really fast you should use any type of binding with binary serialization (netTcp or namedPipe, if you use same host) and ideally different binary serializer . From my experience simply using ProtoBuf .NET can give you 2 times better latency values. Almost all you need is to add Protobuf specific attributes to your data contract and to enable protobuf behavior in config file via extension.

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM