Skip to content

Instantly share code, notes, and snippets.

@StephenCleary
Last active April 17, 2020 03:05

Revisions

  1. StephenCleary renamed this gist Sep 24, 2019. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. StephenCleary renamed this gist Sep 24, 2019. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. StephenCleary revised this gist Sep 24, 2019. 2 changed files with 1 addition and 0 deletions.
    File renamed without changes.
    1 change: 1 addition & 0 deletions _Async WebAPI.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Simple WebAPI app with Console client that shows that async methods do release threads to the thread pool.
  4. StephenCleary renamed this gist Sep 24, 2019. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. StephenCleary revised this gist Jun 17, 2013. 1 changed file with 22 additions and 25 deletions.
    47 changes: 22 additions & 25 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -27,40 +27,37 @@ static async Task MainAsync()
    {
    ServicePointManager.DefaultConnectionLimit = int.MaxValue;

    var sw = new Stopwatch();
    var client = new HttpClient();
    var connections = Environment.ProcessorCount;
    var url = "http://localhost:35697/api/values/";
    int connections;
    var syncUrl = "http://localhost:35697/api/values/";
    var asyncUrl = "http://localhost:35697/api/values/13";

    await client.GetStringAsync(url); // warmup
    sw.Start();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);
    connections = Environment.ProcessorCount;
    Console.WriteLine(" Synchronous time for " + connections + " connections: " +
    await RunTest(syncUrl, connections));

    connections = Environment.ProcessorCount + 1;
    Console.WriteLine(" Synchronous time for " + connections + " connections: " +
    await RunTest(syncUrl, connections));

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);

    url += "13";
    connections = Environment.ProcessorCount;

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);
    Console.WriteLine("Asynchronous time for " + connections + " connections: " +
    await RunTest(asyncUrl, connections));

    connections = Environment.ProcessorCount + 1;
    Console.WriteLine("Asynchronous time for " + connections + " connections: " +
    await RunTest(asyncUrl, connections));
    }

    static async Task<TimeSpan> RunTest(string url, int concurrentConnections)
    {
    var sw = new Stopwatch();
    var client = new HttpClient();

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Start();
    await Task.WhenAll(Enumerable.Range(0, concurrentConnections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);

    return sw.Elapsed;
    }
    }
  6. StephenCleary created this gist Jun 17, 2013.
    4 changes: 4 additions & 0 deletions Example Output
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    Synchronous time for 8 connections: 00:00:01.0194025
    Synchronous time for 9 connections: 00:00:02.0362007
    Asynchronous time for 8 connections: 00:00:01.0413737
    Asynchronous time for 9 connections: 00:00:01.0238674
    34 changes: 34 additions & 0 deletions Global.asax.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Web;
    using System.Web.Http;
    using System.Web.Mvc;
    using System.Web.Optimization;
    using System.Web.Routing;

    namespace MvcApplication2
    {
    // Note: For instructions on enabling IIS6 or IIS7 classic mode,
    // visit http://go.microsoft.com/?LinkId=9394801

    public class WebApiApplication : System.Web.HttpApplication
    {
    protected void Application_Start()
    {
    // Begin Changes
    int workerThreads, ioThreads;
    ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
    ThreadPool.SetMaxThreads(Environment.ProcessorCount, ioThreads);
    // End Changes

    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
    }
    }
    66 changes: 66 additions & 0 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;

    class Program
    {
    static void Main(string[] args)
    {
    try
    {
    MainAsync().Wait();
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex);
    }

    Console.ReadKey();
    }

    static async Task MainAsync()
    {
    ServicePointManager.DefaultConnectionLimit = int.MaxValue;

    var sw = new Stopwatch();
    var client = new HttpClient();
    var connections = Environment.ProcessorCount;
    var url = "http://localhost:35697/api/values/";

    await client.GetStringAsync(url); // warmup
    sw.Start();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);

    connections = Environment.ProcessorCount + 1;

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Synchronous time for " + connections + " connections: " + sw.Elapsed);

    url += "13";
    connections = Environment.ProcessorCount;

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);

    connections = Environment.ProcessorCount + 1;

    await client.GetStringAsync(url); // warmup
    sw.Restart();
    await Task.WhenAll(Enumerable.Range(0, connections).Select(i => client.GetStringAsync(url)));
    sw.Stop();
    Console.WriteLine("Asynchronous time for " + connections + " connections: " + sw.Elapsed);
    }
    }
    28 changes: 28 additions & 0 deletions ValuesController.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http;

    namespace MvcApplication2.Controllers
    {
    public class ValuesController : ApiController
    {
    // Synchronous
    public IEnumerable<string> Get()
    {
    Thread.Sleep(1000);
    return new string[] { "value1", "value2" };
    }

    // Asynchronous
    public async Task<IEnumerable<string>> Get(int id)
    {
    await Task.Delay(1000);
    return new string[] { "value1", "value2" };
    }
    }
    }