Skip to content

Instantly share code, notes, and snippets.

@StephenCleary
Last active April 17, 2020 03:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save StephenCleary/5796697 to your computer and use it in GitHub Desktop.
Save StephenCleary/5796697 to your computer and use it in GitHub Desktop.
Simple WebAPI app with Console client that shows that async methods do release threads to the thread pool.
Simple WebAPI app with Console client that shows that async methods do release threads to the thread pool.
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
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);
}
}
}
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;
int connections;
var syncUrl = "http://localhost:35697/api/values/";
var asyncUrl = "http://localhost:35697/api/values/13";
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));
connections = Environment.ProcessorCount;
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.Start();
await Task.WhenAll(Enumerable.Range(0, concurrentConnections).Select(i => client.GetStringAsync(url)));
sw.Stop();
return sw.Elapsed;
}
}
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" };
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment