title: C# threads when executing many tasks in Task.WhenAll
body: <p>What will happen if, on a single thread, I do this:</p>
  
  <pre class="lang-c# prettyprint-override"><code>await Task.WhenAll(items.select(x =&gt; SomeAsyncMethod(x)))
  
  // Where SomeAsyncMethod is defined like this (writeAsync is pure async io)
  async Task SomeAsyncMethod(Item item){
    await myDevice.writeAsync(...).ConfigureAwait(false);
    //do some cpu intensive stuff...
  }
  </code></pre>
  
  <p>and say there are 10.000 items in <code>items</code>. When each of the <code>SomeAsyncMethod</code> continue after the await, then it does so on a thread from the thread pool. So when many of the <code>SomeAsyncsMethod</code>s return will several threads from the thread pool then be taken simultaneously, or will only a single thread execute "do some CPU intensive stuff" in <code>SomeAsyncMethod</code> at any given moment in this case?</p>
  
  <p>UPDATE: Ok here is a sample program. When I test this on a PC with 8 logical cores, then minthreads is 12 or 13 and maxthreads ends in the 35-40 range. 
  So it looks as if up to 4 threads will be created pr logical core. It does not matter if 10.000 or 100.000 files are created - the same max number of threads is used - maybe this is because all the tasks queue up waiting for access to the file system ?. Please note, that this program will create lots of small files in c:\tmp\asynctest: </p>
  
  <pre><code>using System;
  using System.Collections.Concurrent;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace ConsoleApplication4 {
      internal class Program {
          private static void Main(string[] args) {
              var myDevice = new MyDevice();
              var ints = new List&lt;int&gt;();
              for (var i = 0; i &lt; 10000; i++) {
                  ints.Add(i);
              }
              var task = Task.WhenAll(ints.Select(i =&gt; myDevice.WriteTextAsync(i.ToString())));
              task.Wait();
              Console.WriteLine("Max thread count = " + myDevice.MaxThreadCount);
              Console.WriteLine("Min thread count = " + myDevice.MinThreadCount);
              Console.ReadLine();
          }
      }
  
      public class MyDevice {
          public ConcurrentDictionary&lt;string, string&gt; ThreadIds;
          public int MaxThreadCount;
          public int MinThreadCount = Process.GetCurrentProcess().Threads.Count;
          public async Task WriteTextAsync(string text) {
              var filePath = @"c:\tmp\asynctest\" + text + ".txt";
              var encodedText = Encoding.Unicode.GetBytes(text);
              using (var sourceStream = new FileStream(filePath,
                  FileMode.Append, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) {
                  await sourceStream.WriteAsync(encodedText, 0, encodedText.Length).ConfigureAwait(false);
                  MaxThreadCount = Math.Max(MaxThreadCount, Process.GetCurrentProcess().Threads.Count);
                  MinThreadCount = Math.Min(MinThreadCount, Process.GetCurrentProcess().Threads.Count);
              }
          }
      }
  }
  </code></pre>
  
  <p>Update 2. Now if I start multiple threads that each do lots of aysnc io tasks simultaneously, then it does not look as if more threads in total are used compared to the single threaded example in update 1. In the test I just ran, where 10.000 files are created each by 4 threads, then max threads was 41 and min threads 12 - so there seems to be some central control of how many threads are used for async task continuations. Here is a the example where 4 threads starts 10.000 async operations each:</p>
  
  <pre><code>using System;
  using System.Collections.Concurrent;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace ConsoleApplication4 {
      internal class Program {
          private static void Main(string[] args) {
              var myDevice = new MyDevice();
              var ints = new List&lt;int&gt;();
              const int limit = 10000;
              for (var i = 0; i &lt; limit; i++) {
                  ints.Add(i);
              }
  
              List&lt;Task&gt; jobs = new List&lt;Task&gt;();
              for (var j = 0; j &lt; 4*limit; j+=limit) {
                  var jobid = j;
                  jobs.Add(Task.Run(() =&gt; Runjob(ints, myDevice, jobid)));
              }
              Task.WaitAll(jobs.ToArray());
  
              Console.WriteLine("Max thread count = " + myDevice.MaxThreadCount);
              Console.WriteLine("Min thread count = " + myDevice.MinThreadCount);
              Console.ReadLine();
          }
  
          private static void Runjob(List&lt;int&gt; ints, MyDevice myDevice, int jobid) {
              Console.WriteLine("Starting job " + jobid);
              var task = Task.WhenAll(ints.Select(i =&gt; myDevice.WriteTextAsync((jobid+i).ToString())));
              task.Wait();
              Console.WriteLine("Finished job " + jobid);
          }
      }
  
      public class MyDevice {
          public int MaxThreadCount;
          public int MinThreadCount = Process.GetCurrentProcess().Threads.Count;
          public async Task WriteTextAsync(string text) {
              var filePath = @"c:\tmp\asynctest\" + text + ".txt";
              var encodedText = Encoding.Unicode.GetBytes(text);
              using (var sourceStream = new FileStream(filePath,
                  FileMode.Append, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) {
                  await sourceStream.WriteAsync(encodedText, 0, encodedText.Length).ConfigureAwait(false);
                  MaxThreadCount = Math.Max(MaxThreadCount, Process.GetCurrentProcess().Threads.Count);
                  MinThreadCount = Math.Min(MinThreadCount, Process.GetCurrentProcess().Threads.Count);
              }
          }
      }
  }
  </code></pre>