Why Are WCF Responses Slow and SetMinThreads Does Not Work?


Customers reported the following WCF performance issue recently:


·        A WCF client sends 10 requests concurrently to a self-hosted WCF service on 10 different threads. The service operation is very simple and it simply sleeps for 1 second. But the latencies for the 10 requests on the client side were distributed from 1 to 3.3 seconds. Why is this?


First of all, WCF uses managed I/O threads to handle requests. The CLR ThreadPool keeps a certain number of idle I/O threads from being destroyed. When more I/O threads are needed, they are created by the ThreadPool, which is kind of expensive. The number of idle threads is specified by the “MinIOThreads” setting. You can use the ThreadPool.GetMinThreads() API to check what settings you have for your application. By default in a standalone application, this setting is the number of the CPUs that you have on the machine. For example, on my laptop with 2-core, this setting is 2. I observed the following delay numbers in the above scenario:


Thread 0 takes: 1009 ms


Thread 2 takes: 1286 ms


Thread 3 takes: 1799 ms


Thread 4 takes: 2016 ms


Thread 6 takes: 2241 ms


Thread 5 takes: 2256 ms


Thread 7 takes: 2752 ms


Thread 8 takes: 2766 ms


Thread 9 takes: 2967 ms


Thread 1 takes: 3315 ms


Because of this, you would want to bump up this MinIOThreads setting with the ThreadPool.SetMinThreads() API on the service side, for example:


ThreadPool.SetMinThreads(Environment.ProcessorCount, 10);


You may notice that this still does not solve the above problem with .NET 3.5. Why?


Eric, who is the CLR ThreadPool expert, told me that there was a bug in .NET 3.5. ThreadPool does not honor what SetMinThreads() provides. So the above logic does not work. Fortunately this has been fixed in .NET 4.0 and the Microsoft has provided the following QFE for 3.5:


http://support.microsoft.com/kb/976898


Once you have this QFE installed, you would get much better result:


Thread 1 takes: 1026 ms


Thread 0 takes: 1028 ms


Thread 3 takes: 1081 ms


Thread 4 takes: 1074 ms


Thread 2 takes: 1084 ms


Thread 6 takes: 1072 ms


Thread 5 takes: 1073 ms


Thread 8 takes: 1029 ms


Thread 9 takes: 1021 ms


Thread 7 takes: 1154 ms


The sample code is attached.

WcfParallelSlow.zip

Comments (2)

  1. Rune says:

    Have you guys done anything about concurrency and "reliable sessions"? In 3.5 it was impossible to do what your example does in the case where your server is using BasicHTTPBinding (w/o ReliableSession set).

  2. Harshil says:

    Great, It works fine with Http but after changing type to TcpPipe getting some unknown exception after executing 8-9 threads..

    any idea?