async/await如何在ASP.Net应用程序中提供帮助?

Yaw*_*aza 4 c# asp.net-mvc multithreading threadpool async-await

在MVC控制器的操作方法中使用async/await可以扩展Web应用程序,因为等待Asp.Net线程池的请求线程被释放,以便它可以处理IIS队列中的此工作进程的其他请求.这意味着如果我们将工作进程的队列长度限制为10,并向异步操作发送50-100个请求,则IIS不应返回HTTP 503错误,因为始终存在从Asp.Net线程池到服务器的空闲线程来电请求.

我有一个WebApi进行如下计算:

public class ValuesController : ApiController
{
    public int GetSum(int x, int y, int timeDelay = 1)
    {
        Thread.Sleep(timeDelay*1000);
        int result = x + y;
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

此操作方法只是在将总和结果返回给调用代码之前延迟给定的秒数.非常基本的web api只是为了模仿长时间运行的代码.

接下来是等待结果的MVC异步操作:

public class ThreadStarvationController : Controller
{
    public async Task<ActionResult> CallGetSumWithDelayAsync(int num1 = 5, int num2 = 8, int timeDelay = 60)
    {
        int callingThreadId = Thread.CurrentThread.ManagedThreadId;
        ThreadStarvationModel model = new ThreadStarvationModel();

        string url = "http://localhost:8111/api/values/GetSum?x=" + num1 + "&y=" + num2 + "&timeDelay=" + timeDelay;

        using (HttpClient client = new HttpClient())
        {

            // here still using the same request thread...
            // following line will force await to free up the request thread and wait asynchronouly               //for the response.
            model.ResponseFromWebService = await client.GetStringAsync(url);

            // here we can be on the same request thread or anyother thread... more likely on //another other thread than 
            // request thread.
        }

        int returningThreadId = Thread.CurrentThread.ManagedThreadId;

        model.CallingThreadId = callingThreadId;
        model.ReturningThreadId = returningThreadId;

        return this.View(model);
    }
}
Run Code Online (Sandbox Code Playgroud)

WebApi和MVC托管在IIS上.MVC网站仅限于10个队列请求.

当客户端在15或20个请求之后调用MVC异步方法时,IIS发送HTTP 503错误,这意味着IIS队列已满请求.

以下是调用MVC异步方法的控制台应用程序代码.它安排了30个任务并并行执行.

          List<Task> taskList = new List<Task>();
        for (int x = 0; x < 30; x++)
        {
            string url = "http://localhost:8333/ThreadStarvation/CallGetSumWithDelayAsync?num1=" + x + "&num2=" + x + "&timeDelay=1";

            Task stringDataTask = new Task(() =>
            {
                using (HttpClient webClient = new HttpClient())
                {
                    string data = webClient.GetStringAsync(url).Result;
                    Console.WriteLine("{0}", data);
                }
            });


            taskList.Add(stringDataTask);
        }

        DateTime startTime = DateTime.Now;

        Parallel.ForEach(taskList, item => item.Start());

        Console.WriteLine("================== START {0} ===========================", startTime);

        Task.WaitAll(taskList.ToArray());
        DateTime endTime = DateTime.Now;
        Console.WriteLine("================= THE END {0} ============================", endTime);
Run Code Online (Sandbox Code Playgroud)

当这个运行时,在20个左右的请求后,我收到HTTP 503错误消息.

如果我使用同步MVC操作,结果仍然相同.我知道使用async/await会在await之前和之后使用不同的线程.

我想要证明的是,使用async/await将扩展Web应用程序.

jlv*_*ero 7

我认为你混淆游泳池队列.ASP.NET请求有5个位置可以在IIS服务器上排队.

  1. 应用程序池队列
  2. IIS工作进程
  3. CLR线程池队列
  4. 集成模式全局队列
  5. 经典模式应用队列

您设置为10的队列长度是HTTP.SYS:应用程序池队列.

当您使用async/awat时,您正在使用ASP.NET:CLR线程池队列.

这就是为什么即使使用async/await也会出现503错误的原因.

另一方面,这里有一篇关于使用async/await来scalling web应用程序的精彩文章可以帮到你.

[编辑]我刚刚发现这篇关于请求排队的文章也可以提供帮助.

  • @ user1039644:实际上有两种不同的任务:委托任务在线程池上执行; 它们是大多数人想到的那类任务.但也有Promise Tasks,它不会在任何地方"运行"; 从`async`方法返回的任务是Promise Tasks.我有几篇博文[这里](http://blog.stephencleary.com/2014/04/a-tour-of-task-part-0-overview.html)和[这里](http:// blog/2014/06/A-巡回的任务部分-3- status.html).stephencleary.com.此外,我的博客文章[没有线程](http://blog.stephencleary.com/2013/11/there-is-no-thread.html)可能会更好地解释它. (2认同)