ASP.NET C#5 Asynchronous Web Applications Using Async & Await

前端 未结 1 1414
有刺的猬
有刺的猬 2021-02-02 02:07

Having researched the concept of asynchronous web development, specifically from this source, I created a sample application to prove the concept.

The solution is compos

相关标签:
1条回答
  • 2021-02-02 02:59

    I think there's a pretty good chance you're not testing what you think you're testing. From what I can gather, you're trying to detect releases back to the thread pool by comparing timings and deducing thread injection.

    For one thing, the default settings for the thread pool on .NET 4.5 are extremely high. You're not going to hit them with just 10 or 100 simultaneous requests.

    Step back for a second and think of what you want to test: does an async method return its thread to the thread pool?

    I have a demo that I show to demonstrate this. I didn't want to create a heavy load test for my demo (running on my presentation laptop), so I pulled a little trick: I artificially restrict the thread pool to a more reasonable value.

    Once you do that, your test is quite simple: perform that many simultaneous connections, and then perform that many plus one. The synchronous implementation will have to wait for one to complete before starting the last one, while the asynchronous implementation will be able to start them all.

    On the server side, first restrict the thread pool threads to the number of processors in the system:

    protected void Application_Start()
    {
        int workerThreads, ioThreads;
        ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
        ThreadPool.SetMaxThreads(Environment.ProcessorCount, ioThreads);
        ...
    }
    

    Then do the synchronous and asynchronous implementations:

    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" };
        }
    }
    

    And finally the client testing code:

    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);
    }
    

    On my (8-logical-core) machine, I see output like this:

    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
    

    Which clearly shows that the asynchronous method is returning its thread to the thread pool.

    0 讨论(0)
提交回复
热议问题