67

I'm stress testing a web app and have set up a windows test program that spins up a number of threads and sends out a web request on each one.

Problem is I get the following output:

01/09/09 11:34:04 Starting new HTTP request on 10
01/09/09 11:34:04 Starting new HTTP request on 11
01/09/09 11:34:04 Starting new HTTP request on 13
01/09/09 11:34:05 Starting new HTTP request on 14
01/09/09 11:34:05 Starting new HTTP request on 11
01/09/09 11:34:05 11 has finished!
01/09/09 11:34:05 Starting new HTTP request on 13
01/09/09 11:34:05 13 has finished!
01/09/09 11:34:05 Starting new HTTP request on 14
01/09/09 11:34:05 14 has finished!
01/09/09 11:34:05 Starting new HTTP request on 11
01/09/09 11:34:05 11 has finished!
01/09/09 11:34:05 Starting new HTTP request on 14
01/09/09 11:34:05 14 has finished!
01/09/09 11:34:05 Starting new HTTP request on 13
01/09/09 11:34:05 13 has finished!
01/09/09 11:34:05 Starting new HTTP request on 15
01/09/09 11:34:06 Starting new HTTP request on 11
01/09/09 11:34:06 11 has finished!
01/09/09 11:34:06 Starting new HTTP request on 14
01/09/09 11:34:06 14 has finished!

which sort of looks like there's a maximum of 5 threads, even if I create 100 as so:

int numberOfThreads = Convert.ToInt32(txtConcurrentThreads.Text);

    List<BackgroundWorker> workers = new List<BackgroundWorker>();

    for (int N = 0; N < numberOfThreads; N++)
    {

        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        workers.Add(worker);
    }


    foreach(BackgroundWorker worker in workers)
    {
        worker.RunWorkerAsync();
    }

Can anyone enlighten me as to what is going on?

Thanks

EDIT: If as suggested I sleep for 5 seconds, instead of httpwebrequest, then I do get more threads firing but not as many as I would have expected:

01/09/09 11:56:14 Starting new HTTP request on 7
01/09/09 11:56:14 Starting new HTTP request on 11
01/09/09 11:56:15 Starting new HTTP request on 12
01/09/09 11:56:15 Starting new HTTP request on 13
01/09/09 11:56:16 Starting new HTTP request on 14
01/09/09 11:56:16 Starting new HTTP request on 15
01/09/09 11:56:17 Starting new HTTP request on 16
01/09/09 11:56:17 Starting new HTTP request on 17
01/09/09 11:56:18 Starting new HTTP request on 18
01/09/09 11:56:19 Starting new HTTP request on 7
01/09/09 11:56:19 7 has finished!
01/09/09 11:56:19 Starting new HTTP request on 11
01/09/09 11:56:19 11 has finished!
01/09/09 11:56:19 Starting new HTTP request on 19
01/09/09 11:56:20 Starting new HTTP request on 20
01/09/09 11:56:20 Starting new HTTP request on 12
01/09/09 11:56:20 12 has finished!

It still looks like I'm only getting 2 threads starting every second, which seems mighty slow to me. I suppose the Console.WriteLine could be a problem?

EDIT: I set

ThreadPool.SetMinThreads(100, 4); 

and

System.Net.ServicePointManager.DefaultConnectionLimit = 100;

and got the following results:

01/09/09 14:00:07 Starting new HTTP request on 11
01/09/09 14:00:07 Starting new HTTP request on 81
01/09/09 14:00:07 Starting new HTTP request on 82
01/09/09 14:00:07 Starting new HTTP request on 79
01/09/09 14:00:07 Starting new HTTP request on 83
01/09/09 14:00:07 Starting new HTTP request on 84
01/09/09 14:00:07 Starting new HTTP request on 85
01/09/09 14:00:07 Starting new HTTP request on 87
01/09/09 14:00:07 Starting new HTTP request on 88
...
01/09/09 14:00:07 84 has finished! Took 323.0323 milliseconds
01/09/09 14:00:08 88 has finished! Took 808.0808 milliseconds
01/09/09 14:00:08 96 has finished! Took 806.0806 milliseconds
01/09/09 14:00:08 94 has finished! Took 806.0806 milliseconds
01/09/09 14:00:08 98 has finished! Took 801.0801 milliseconds
01/09/09 14:00:08 80 has finished! Took 799.0799 milliseconds
01/09/09 14:00:08 86 has finished! Took 799.0799 milliseconds
01/09/09 14:00:08 92 has finished! Took 799.0799 milliseconds
01/09/09 14:00:08 100 has finished! Took 812.0812 milliseconds
01/09/09 14:00:08 82 has finished! Took 1010.101 milliseconds

so was able to push out a whole lot of web requests concurrently. Which seemed to queue (calling out to an STA COM+ server) so that's what I expected.

Thanks for your help

Duncan
  • 10,218
  • 14
  • 64
  • 96
  • 1
    I have a question to your solution here. according to msdn (https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit(v=vs.110).aspx ), the default value is the max int32, which is way larger than 100 you set here. How does it make difference even when you didn't set it to 100? I mean, I kind of doubt if you solved it by setting ServicePointManager's default connection limit or rather by setting connectionManagement element in the first answer. – foxwendy Aug 21 '15 at 14:20
  • 1
    @foxwendy Yeah, MSDN says it's. int.MaxValue, when I have tried it in .NET 4.5 it's just **2** by default. – xmedeko Dec 11 '15 at 16:12

4 Answers4

76

Are all (or most) of your requests going to the same host by any chance? There's a built-in limit on a per-host basis. You can change this in app.config in the system.Net connectionManagement element.

The other thing is that the thread pool only ramps up its number of threads gradually - it starts a new thread every half second, IIRC. Could that be what you're seeing? Try getting rid of HttpWebRequest from the equation - just sleep for a couple of seconds instead...

I suspect the latter problem is the one you're initially running into, but the first one is going to cause you problems as well.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes, they are all going to localhost. – Duncan Sep 01 '09 at 10:53
  • I don't know whether the limit applies to localhost... but it's definitely something to be aware of. See my edit for a link to the appropraite app.config element. – Jon Skeet Sep 01 '09 at 10:56
  • 1
    Would this limit apply to a WCF client making requests to a WCF service, using an HTTP binding? My assumption would be yes...? – John B Aug 02 '12 at 15:48
  • Also, it looks like there is a Windows registry setting for WinInet for `MaxConnectionsPerServer` that defaults to 2 for an HTTP 1.1 server. Would this web.config setting override that, or would I still need to up the registry setting too? – John B Aug 02 '12 at 15:51
  • 1
    The Windows registry setting applies to WinINET only; .NET ignores it. – EricLaw Jan 18 '13 at 20:23
  • OMG thank you! I had an application that downloaded a bunch of reports from the internet in parallel. I had solved all concurrency issues, all database connections, and yet it was still running much slower at scale than it should have. This was the issue. Thank you! Thank you! Thank you! – Sam Mar 17 '18 at 20:44
57

There is a limit in the number of simultaneous outgoing HTTP connections. I think you can control this by using the System.Net.ServicePointManager.DefaultConnectionLimit static property before creating the HttpWebRequest objects.

Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
14

I haven't heard much about this for .NET Core. ServicePointManager was not included in .NET Core 1, but appears to be back again in version 2. However, for the HttpClient, you can also set the maximum number of connections like this:

new HttpClient(new HttpClientHandler
                {
                    MaxConnectionsPerServer = 100
                })
cbp
  • 25,252
  • 29
  • 125
  • 205
7

If i write below tag in windows config than will it be executed every time when below code is executed. So every time below code is executed i will be allowed to have max 1000000 no of parallel request/response.

HttpWebRequest POSTRequest = (HttpWebRequest)WebRequest.Create("http://yahoo.com");

Tag

<connectionManagement>
 <clear/>
 <add address="*" maxconnection="1000000" />
</connectionManagement>
Ralph Willgoss
  • 11,750
  • 4
  • 64
  • 67
user220550
  • 79
  • 1
  • 2
  • I can confirm the above change in App.config allows multiple HttpWebRequests to occur. i.e. put maxconnection="" – Vinnie Amir May 09 '18 at 01:48