title: Why wrapping awaitable async method into Task.Run improves the performance at least twice?
body: <p>I have a simple implementation of HTTP Server. The code is shown below. It was tested on the server machine with 32cores. If I wrap the processContext method into Task.Run call, then the performance doubles (at least). Considering that this gave me a performance gain in this particular case, I am confused now: having some method returning a Task, which I don't wish to wait for, what strategy should I follow? Should I call it directly or should I wrap inside Task.Run?</p>
  
  <pre><code>class Program
  {
      private static ConcurrentBag&lt;DateTime&gt; _trails = new ConcurrentBag&lt;DateTime&gt;();
  
      static void Main(string[] args)
      {
          Console.WriteLine($"Is server GC: {(GCSettings.IsServerGC ? "true" : "false")}");
  
          string prefix = args[0];
  
          CancellationTokenSource cancellationSource = new CancellationTokenSource();
  
          HttpListener httpListener = new HttpListener();
  
          httpListener.Prefixes.Add(prefix);
  
          httpListener.Start();
  
          Task.Run(async () =&gt;
          {
              while (!cancellationSource.Token.IsCancellationRequested)
              {
                  HttpListenerContext context = null;
  
                  try
                  {
                      context = await httpListener.GetContextAsync();
  
                      if (cancellationSource.Token.IsCancellationRequested)
                      {
                          context.Response.Abort();
  
                          break;
                      }
                  }
                  catch (ObjectDisposedException)
                  {
                      return;
                  }
                  catch (HttpListenerException ex)
                  {
                      if (cancellationSource.Token.IsCancellationRequested &amp;&amp; ex.ErrorCode == 995)
                      {
                          break;
                      }
  
                      throw;
                  }
  
                  // Uncommenting below line and commenting the next one improves the performance at least twice
                  // Task childProcessingTask = Task.Run(async () =&gt; await processContext(context));
  
                  var dt = processContext(context);
              }
          });
  
          using (Timer t = new Timer(o =&gt; Console.Title = $"Async Server: {_trails.Count}", null, 0, 5000))
          {
              Console.WriteLine("Running...");
  
              Console.ReadLine();
  
              cancellationSource.Cancel();
  
              Console.WriteLine("Stopped accepting new request. Waiting for pending requests...");
  
              Console.WriteLine("Stopped");
  
              httpListener.Close();
          }
  
          var gTrails = _trails.GroupBy(t =&gt; new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, 0))
              .Select(g =&gt; new { MinuteDt = g.Key, Count = g.Count() })
              .OrderBy(x =&gt; x.MinuteDt).ToList();
  
          gTrails.ForEach(x =&gt; Console.WriteLine($"{x.MinuteDt:HH:mm}\t{x.Count}"));
  
          if (gTrails.Count &gt; 2)
          {
              decimal avg = gTrails.Take(gTrails.Count - 1).Skip(1).Average(g =&gt; (decimal)g.Count);
              Console.WriteLine($"Average: {avg:0.00}/min, {avg / 60.0m:00.0}/sec");
          }
  
          Console.ReadLine();
      }
  
      private static async Task processContext(HttpListenerContext context)
      {
          DateTime requestDt = DateTime.Now;
          Stopwatch sw = Stopwatch.StartNew();
  
          string requestId = context.Request.QueryString["requestId"];
  
          byte[] requestIdBytes = Encoding.ASCII.GetBytes(requestId);
  
          context.Response.ContentLength64 = requestIdBytes.Length;
  
          await context.Response.OutputStream.WriteAsync(requestIdBytes, 0, requestIdBytes.Length);
  
          try
          {
              context.Response.Close();
          }
          catch { }
  
          _trails.Add(requestDt);
      }
  }
  </code></pre>