1

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; i.e. 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.

Amit
  • 1,836
  • 15
  • 24

2 Answers2

3

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, e.g. 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.

Community
  • 1
  • 1
Markus
  • 20,838
  • 4
  • 31
  • 55
  • I am hosting the WCF inside of a windows service; so IIS is not involved. IF WINDOWS did create such bad framework that a call, which is equivalent to a RPC, takes 2 seconds, then I am done writing WCF, before I even began. Even plain IIS pages are faster than that. All I need is a simple cross process call; RPC/COM style. – Amit Nov 17 '15 at 07:36
  • Use NetTcpBinding binding instead of SOAP binding – Prasanth V J Nov 17 '15 at 07:55
  • @Amit WCF is not by any stretch designed for performance. You must remember its not designed for IPC, but rather RPC, where latency takes up the lion's share of the runtime. It is also very high level, and abstract/configurable, which is why on startup, a lot of code is needed to run to build the service client proxy (serializer and channel factory). WCF is not a bad framework, its just not a performant framework. Even so I am very surprised that it takes 2 seconds to start up the first call. Could you explain the test setup/contract size? – Aron Nov 17 '15 at 07:55
  • I do not exactly know test setup/contract size. The client is the small client I pasted above. The service is dummy; taken straight from MSDN; it implements only one function. Which is also kind of dummy - takes a int parameter and straight echoes "you entered i". So contract should be minimal. – Amit Nov 17 '15 at 08:27
  • If NOT WCF, where do I begin to get COM style RPC – Amit Nov 17 '15 at 08:28
  • @Amit if you only want to have a cross process call on the same computer, use NetNamedPipesBinding. This is the most efficient binding in WCF. I've extended my answer with some more suggestions. .NET remoting is a very basic way to interoperate with other .NET clients, but as I wrote, I'd always favor WCF over this. – Markus Nov 17 '15 at 08:30
0

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!

Community
  • 1
  • 1
Mimas
  • 525
  • 3
  • 7
  • The WCF service is hosted in a windows service; so it is always alive. I will try difference serialization though. The use case is client1 calls this service, once in its life time. Then client2 calls; and so on. 1000s of short lived clients. – Amit Nov 18 '15 at 13:11
  • are all clients distributed and placed on different hosts? If so, I can say only "I am sorry". If the clients are simply recreated inside one application, you can cache channelfactory and reuse it. But unfortunately this is absolute obvious: any first call to any remote service (regardless which type of service it is, database, redis, soap service etc) requires some resources initialization like sockets, listeners, threads. It is always slow. And 1 ms is also too optimistic demands, I am afraid not reachable. Just measure the network ping, is it 1 ms? – Mimas Nov 18 '15 at 13:26
  • The clients are on same machine as service. I just needed to host something in the service; precisely for reasons you outlined. I have an AmazonDynamoDB connection, and rather than each client having to initialize a connection to Dynamo, I thought that the clients would call a service locally, that local service making calls to Dynamo, reusing Dynamo DB connection – Amit Nov 18 '15 at 15:17