0

I created a .Net Web Api with two controllers that do the same thing (purposefully very slow network calls). One is synchronous and one is asynchronous. You can find the code here: https://github.com/jkruer01/SyncVsAsync

The important difference between the 2 controllers is this single line of code with a WebClient:

Synchronous

var content = client.DownloadString(url);

Asynchronous

var content = await client.DownloadStringTaskAsync(url);

Pretty basic stuff...

Then I created a console app the fires 50 simultaneous requests to either the sync or async controller. I expected the async controller to complete more simultaneous requests but I found the exact opposite to be true. The sync controller completed about 25 out of 50 successfully. The async controller only completed about 10 out of 50 successfully.

Why is this? I thought the purpose of the async code was that it could handle more simultaneous requests.

I'm stumped.

jkruer01
  • 2,175
  • 4
  • 32
  • 57
  • could the limitation be on the "server" where it has trouble handling multiple requests at the same time which causes the slowdown? – JanR Nov 29 '16 at 00:34
  • 5
    Please post the relevant part of your code here. It is not fair for you to ask people to search through your code. Narrow down the problem to a specific area and then paste that here. – CodingYoshi Nov 29 '16 at 00:36
  • I am confused. In the title for the question you're talking about speed yet in the body you're talking about success/fail difference. Can you paste relevant parts of your code with some comments and results? – agfc Nov 29 '16 at 00:45
  • I updated my question to include specific code differences. – jkruer01 Nov 29 '16 at 00:50
  • You didn't add the right amount of code. Specifically, you're using await inside a loop. That means you will never have two simultaneous requests - "await" means to stop the execution of the current function until the awaitable is ready. So each iteration of the loop has to be complete before the function can resume and do another iteration. It's asynchronous but it's still happening in a completely serial fashion. – PMV Nov 29 '16 at 01:45
  • I know that a single request is happening in a serial fashion, but the point is to allow multiple simultaneous requests from multiple users. – jkruer01 Nov 29 '16 at 02:29
  • async-await does has more instantiations and does more work. async-await is not about performance. It's about availability. You pay the cost of context switching to release the thread for other work. – Paulo Morgado Nov 29 '16 at 06:46
  • @PauloMorgado, `async-await` can be about performance too. In ASP.NET specially. `async-await` will release thread for other requests while controller waiting response from database. Which give possibility to faster handle multiply requests. – Fabio Nov 29 '16 at 20:36
  • @Fabio, each request will be slower but will handle more concurrent requests. Thus, availability over performance. – Paulo Morgado Nov 30 '16 at 07:33
  • @PauloMorgado - right, it was wrong example. Another try: with `async/await` I can run two queries to the database(with duration 2 and 3 seconds) and get result after 3 seconds, where synchronous execution will take 5 seconds. – Fabio Nov 30 '16 at 08:02
  • @Fabio, that's because you're running them in parallel, not because they are asynchronous. Each one of them will take longer and consume more resources as if they were synchronous. – Paulo Morgado Nov 30 '16 at 13:31
  • @PauloMorgado That is my point, I would expect the async controller to be able to complete more requests than the synchronous controller. However, I am seeing the exact opposite. The synchronous controller completes more requests successfully than the asynchronous one. Why is this? – jkruer01 Dec 05 '16 at 17:01
  • What happens to the requests that fail? Are you getting errors? – mxmissile Dec 05 '16 at 17:18
  • @mxmissile They are timing out after 120 seconds. – jkruer01 Dec 05 '16 at 17:20
  • Where are you measuring the number of completed requests? On the client or on the server? If you're measuring on the client and getting timeouts, your measurement is not valid. – Paulo Morgado Dec 05 '16 at 22:54

2 Answers2

3

Problem is with the http requests, by default you have a limit of two concurrent calls, that's why it's taking longer, see the following docs:

http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx https://msdn.microsoft.com/en-us/library/system.net.servicepoint.aspx

And also this: Trying to run multiple HTTP requests in parallel, but being limited by Windows (registry)

Try changing that value :)

Community
  • 1
  • 1
  • I will give that a try and let you know what I find out. Thanks! – jkruer01 Nov 29 '16 at 00:50
  • I added this line to my startup class but it still didn't fix the problem. System.Net.ServicePointManager.DefaultConnectionLimit = 1000; – jkruer01 Dec 05 '16 at 16:54
  • It made the synchronous code run faster and allow more requests but the async code is still completing fewer requests successfully. – jkruer01 Dec 05 '16 at 16:54
1

I solved the problem. The issue turned out to be the fact that I was running the code from Visual Studio. Even though I was running it in "Release" mode it was doing something that altered the behavior (I don't know what). I "Published" the code and then ran it outside of Visual Studio and it ran exactly as I would have expected it to. Thanks for all the help and suggestions!

jkruer01
  • 2,175
  • 4
  • 32
  • 57
  • nice, glad it worked :) ... it will be a good idea to update the github repo with the new changes too – Christian Melendez Dec 06 '16 at 18:32
  • Thanks for reminding me. I just pushed the changes. I also made a blog post about it. http://jeremykruer.com/why-my-synchronous-api-scaled-better-than-my-asynchronous-api/ – jkruer01 Dec 06 '16 at 19:25
  • nice!!! thanks for the reference :) ... and also I'm glad it worked, another way to test this could be by using this: https://github.com/dotnet/BenchmarkDotNet give it a look, well written by the way – Christian Melendez Dec 07 '16 at 15:18