async / await 如何在 ASP.Net 应用程序中提供帮助?
Posted
技术标签:
【中文标题】async / await 如何在 ASP.Net 应用程序中提供帮助?【英文标题】:How async / await can help in ASP.Net application? 【发布时间】:2015-03-07 11:14:42 【问题描述】:在 MVC 控制器的 action 方法中使用 async / await 可以扩展 Web 应用程序,因为在 await 时,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;
此操作方法仅延迟给定的秒数,然后将总和结果返回给调用代码。非常基本的 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);
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);
当它运行时,大约 20 个请求后,我收到 HTTP 503 错误消息。
如果我使用同步 MVC 动作,结果还是一样的。我知道在 async / await 之前和之后使用不同的线程。
我想证明的是,使用 async / await 将扩展 Web 应用程序。
【问题讨论】:
哪个 MVC 抛出了 503?你的ThreadStarvationController
控制器?您的控制器是否托管在不同的应用程序池中?
如果您的 API 托管在与您的 Web 应用程序相同的应用程序池下,则它共享一个线程池。这意味着 - 当用于执行 MVC 操作的线程被释放时 - 您的 API 仍在使用 n
线程。
WebAPI 和 MVC 网站都在不同的应用程序池中,因此是独立的工作进程。
Yuval Itzchakov:ThreadStarvationController 控制器托管在其自己的应用程序池中,并且将 IIS 池队列长度限制为 10。是的 MVC 和 WebApi 都托管在具有自己的应用程序池的 IIS 上。
【参考方案1】:
我认为您混淆了池队列。 ASP.NET 请求可以在 IIS 服务器上排队的 5 个位置。
-
应用程序池队列
IIS 工作进程
CLR 线程池队列
集成模式全局队列
经典模式应用队列
您设置为 10 的队列长度是 HTTP.SYS: 应用程序池队列。
当您使用 async/awat 时,您使用的是 ASP.NET:CLR 线程池队列。
这就是为什么即使使用 async/await 也会出现 503 错误的原因。
另一方面,here there is a wonderful article 关于使用 async/await 调用 Web 应用程序可以帮助您。
[编辑] 我刚刚发现 this article 关于请求排队也有帮助。
【讨论】:
谢谢 jlvaquero。我已经阅读了“Stephen Cleary 的文章,那是我决定编写这个应用程序的时候。从你的回答来看,ASP.Net 的请求线程和 await 执行的后台线程是否取自 Asp.Net 线程池?跨度> @user1039644:没有“等待执行的后台线程”。await
的全部意义在于它不使用线程。
@Stephen Cleary。不确定OP是否理解我。我不是该领域的专家。你能比我更清楚地说明情况吗?
@user1039644:我不确定你为什么会看到 503;您的示例中有很多活动部件。我有一个简单的概念验证测试here。关于您的await
问题:await Method()
与var task = Method(); await task;
相同,因此该方法实际上在 await
之前调用。
@user1039644:实际上有两种不同的任务:委托任务在线程池上执行;他们是大多数人想到的那种任务。但也有 Promise Tasks,它不会在任何地方“运行”;从async
方法返回的任务是 Promise 任务。我有几篇博文here 和here。另外,我的博文There Is No Thread 可能会更好地解释它。以上是关于async / await 如何在 ASP.Net 应用程序中提供帮助?的主要内容,如果未能解决你的问题,请参考以下文章
通过 ASP.NET Web API 有效地使用 async/await
深入理解 ASP.NET MVC 上的 async/await
为啥总是在 asp.net mvc 中同步异步操作(async await)
asp.net webform中使用async,await实现异步操作
asp.net webform中使用async,await实现异步操作
使用 async/await 并从 ASP.NET Web API 方法返回 Task<HttpResponseMessage>