-4

I have a long work

    var works = ...
    List<FormatObject> ret = new List<FormatObject>();
    foreach (var w in works)
    {
       l.AddRange(await Info.GetInfo(w));
    }
    return Ok(ret);

It's took approximately 76 seconds.

I tried with parallel Task.WhenAll:

   var works ...
   var ret = await Task.WhenAll(works.Select(Info.GetInfo));
   return Ok(ret);

It's also took approximately 76 seconds. So Task.WhenAll is not faster than foreach loop. I thought Task.WhenAll does the work in parallel, so should be faster than foreach which do sequentially. What was I wrong? How can I execute my work in parallel and get the result returned in just one second?

Bas
  • 26,772
  • 8
  • 53
  • 86
Minh Giang
  • 631
  • 9
  • 28
  • 4
    No. [asynchronous programming](https://learn.microsoft.com/en-us/dotnet/csharp/async) is not used for this purpose. You need to read about parallel processing and [Parallel.ForEach](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-simple-parallel-foreach-loop) Loop. – Salah Akbari Sep 13 '17 at 18:00
  • I tried Parallel.ForEarch, but I need return result from my work, but Parallel.ForEach return immediately with no result – Minh Giang Sep 13 '17 at 18:02
  • 2
    also `List` is not thread safe. – Daniel A. White Sep 13 '17 at 18:02
  • 5
    `Task.WhenAll` doesn't *do work in parallel*, rather, it simply provides a way for you to know when all of the provided tasks have finished. You need to provide a series of already working tasks (which may or may not be able to do their work in parallel) to it for it to do that. – Servy Sep 13 '17 at 18:03
  • 3
    @S.Akbari That's not true at all. While it's true that asynchronous work doesn't *need* to do things in parallel, it certainly *can* do things in parallel, and you certainly don't need something like `Parallel.ForEach`, which does a very specific operation, namely CPU bound work on a collection of items in which each item's value can be independantly processed. That plausibly isn't the case here (this looks like IO bound work). – Servy Sep 13 '17 at 18:04
  • 2
    @DanielA.White The List is never manipulated from multiple threads at the same time in the original code, and the second snippet doesn't use a list. – Servy Sep 13 '17 at 18:05
  • 2
    I am guessing Info.GetInfo is [I/O bound](https://stackoverflow.com/questions/868568/what-do-the-terms-cpu-bound-and-i-o-bound-mean) like database or service call? – Slai Sep 13 '17 at 18:23
  • 2
    @MinhGiang can you repeat your test with setting `ServicePointManager.DefaultConnectionLimit` to a larger value which 2 by default. (If your requests are to the same site) – L.B Sep 13 '17 at 22:59
  • @L.B I'm using asp netcore. Where can I set up ServicePointManager.DefaultConnectionLimit ? – Minh Giang Sep 14 '17 at 02:02

1 Answers1

4

This has nothing to do with WhenAll at all. You called Info.GetInfo a whole bunch of times, and you called it in such a way that you started subsequent calls without requiring the earlier calls to have finished. You then, after starting all of them, used WhenAll to be notified when they had all finished.

Whether the work is able to be done in parallel is entirely based on the implementation of Info.GetInfo. If the internal implementation of that operation, whatever it is, cannot allow multiple invocations to do productive work in parallel (possibly by using asynchronous synchronization mechanisms) then running a whole bunch of them at once won't speed the program up. Another possibility is that the method isn't actually asynchronous (even though it's signature indicates that it ought to be asynchronous) and it might not actually be returning the Task to you until the work is done, rather than quickly returning a Task and doing the work later, as it ought to do.

Servy
  • 202,030
  • 26
  • 332
  • 449