Once in the comments, VladD shared information that one of his colleagues, a network programmer, had moved from multi-threaded to asynchronous network programming. I would like to use the example of a specific task to find out how much asynchrony will gain from multithreading.

Task: take one of the simple network protocols - RFB . We need to simultaneously connect to 10 000 servers with RFB on board, and find out the version of RFB .

How to implement this multithreadedly - I know, but how to implement it asynchronously? And how much, in this problem, asynchrony will win? The implementation of RFB itself is not needed, we need an example of executing 10 000 simultaneous asynchronous requests.


Tested 3 code variants:

  • Multithreaded (changed the breakdown of the list to several - on a thread-safe queue to level the chances)

  • Asynchronous

  • Asynchronous ( Throttling pattern)

Results (checking 300 000 IP addresses):

  • Multi-threaded: 3 minutes 18 seconds
  • Asynchronous: 1 minute 27 seconds
  • Asynchronous ( Throttling pattern): when it has exceeded 6 minutes, I closed the program and did not measure further. Speed ​​can be achieved only by using the level of parallelism - the size of the entire list, but then the meaning of the very use of the pattern is lost. Those. the implementation from andreycha , if you use the level of parallelism less than the size of the list - it works longer than even the multi-threaded version. Perhaps this is just моя mistake, orreycha error.

Conclusion:

  • Standard asynchronous implementation works more than 2 times faster than multi-threaded.
  • Comments are not intended for extended discussion; conversation moved to chat . - PashaPash

1 answer 1

About asynchrony and its benefits here . In short - while the request went to the network and did not come back, we are not blocking the threads on our computer. So 10,000 addresses can be fully processed, for example, in several threads.

Running 10,000 simultaneous requests is, of course, brute force. But it is quite normal to run, say, fifty or hundred simultaneous requests. Such a pattern is called throttling (or in automotive terms, throttling: D). Those. skip the entire amount of tasks little by little. This approach allows you to slightly load the channel when sending requests and the machine when receiving and parsing answers. Sample code might look like this:

 public async Task CheckServers() { var servers = new List<string>(10000) { ... }; const int ConcurrencyLevel = 100; // запускаем первые 100 запросов var tasks = servers.Take(ConcurrencyLevel).Select(GetVersion).ToList(); int nextIndex = ConcurrencyLevel; while (tasks.Count > 0) { // дожидаемся завершения любого запроса var completedTask = await Task.WhenAny(tasks); // удаляем его из списка tasks.Remove(completedTask); // добавляем новый запрос, если таковые остались if (nextIndex < servers.Count) { tasks.Add(GetVersion(servers[nextIndex++])); } string rfbVersion = await completedTask; // работаем с версией } } private async Task<string> GetVersion(string server) { // тут асинхронная реализация обращения к серверу по RFB и возвращение версии } 

An important question is the correct asynchronous implementation of a call to the server using the RFB protocol. If you use a library, it must support asynchrony. If you implement this functionality yourself (for example, on sockets), then you need to use asynchronous socket functions.

UPD

It turned out that the requests / responses from the vehicle are so lightweight that in this case throttling works more slowly than if you send all the requests at once. However, this pattern may still be useful when it is necessary to limit the number of outgoing requests and / or the number of processed responses (for example, if the analysis of answers loads the processor heavily / requires a lot of memory).

  • Hmm, Ie it turns out there will be no winnings? Resources at the test server - in bulk. But I don’t see sense from 500-1000 simultaneous asynchronous calls to servers. They will not load the server by 20%. And to redo synchronous work with RFB in asynchronous is a waste of time. - Alexis
  • one
    @Alexis and you try. And you will see if there will be a gain - both in terms of load (today they gave a good server, bad tomorrow), and in terms of execution time. And then tell us. - andreycha
  • one
    @VladD is reasonable. I wrote about throttling on the first version of the question, where there were no details (neither the code, nor the clarifications in the comments). - andreycha
  • 2
    @Alexis is understandable. Well, then in your case throttling is really not needed. Thanks for the published results. - andreycha
  • one
    @nikita, that link is dead, here is a new one: sendspace.com/file/mxw469 - Alexis