[英]Synchronous Web Api and response time depending on the thread and request count
我正在使用同步/异步来更好地学习它们,并遇到了一件我无法解释的事情。 我已经设置了带有两个端点的 Web Api 项目,这些端点从数据库中读取数据。 一个是同步的,另一个是异步的。 两者都执行相同的操作,在数据库端需要大约 5 秒的时间(故意限制)。 我还根据线程限制了 Web 服务器:
ThreadPool.SetMinThreads(2, 2);
ThreadPool.SetMaxThreads(2, 2);
Currenyly 我担心同步方法的行为, async 像我期望的那样工作。
当我同时向同步端点发送 3 个请求时,我在 5 秒内得到 2 个响应,在 10 秒内得到 1 个响应,这对我来说是合乎逻辑的:
但是,当我同时向同步端点发送 4 个请求时,我最终得到 4 个响应,它们都需要 10 秒(但我预计 2 个是 5s,其他 2 个是 10s)
在 Web 服务器日志中,我看到这 4 个请求实际上是同步处理的,响应时间约为 5 秒:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://localhost:57128/test/syncDb info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://localhost:57128/test/syncDb info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3] Route matched with {action = "GetSyncDb", controller = "Test"}. Executing controller action with signature System.String GetSyncDb() on controller WebApiAsyncAwait.Controllers.TestController (WebApiAsyncAwait). info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3] Route matched with {action = "GetSyncDb", controller = "Test"}. Executing controller action with signature System.String GetSyncDb() on controller WebApiAsyncAwait.Controllers.TestController (WebApiAsyncAwait). info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1] Executing ObjectResult, writing value of type 'System.String'. info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1] Executing ObjectResult, writing value of type 'System.String'. info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2] Executed action WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait) in 5008.3885ms info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2] Executed action WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait) in 5010.472000000001ms info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished in 5026.9979ms 200 text/plain; charset=utf-8 info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished in 5032.421200000001ms 200 text/plain; charset=utf-8 info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://localhost:57128/test/syncDb info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://localhost:57128/test/syncDb info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3] Route matched with {action = "GetSyncDb", controller = "Test"}. Executing controller action with signature System.String GetSyncDb() on controller WebApiAsyncAwait.Controllers.TestController (WebApiAsyncAwait). info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3] Route matched with {action = "GetSyncDb", controller = "Test"}. Executing controller action with signature System.String GetSyncDb() on controller WebApiAsyncAwait.Controllers.TestController (WebApiAsyncAwait). info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1] Executing ObjectResult, writing value of type 'System.String'. info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1] Executing ObjectResult, writing value of type 'System.String'. info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2] Executed action WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait) in 5007.105500000001ms info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2] Executed action WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait) in 5005.6482000000005ms info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'WebApiAsyncAwait.Controllers.TestController.GetSyncDb (WebApiAsyncAwait)' info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished in 5021.8341ms 200 text/plain; charset=utf-8 info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished in 5023.8319ms 200 text/plain; charset=utf-8
端点代码:
[HttpGet]
[Route("syncDb")]
public string GetSyncDb()
{
string connStr = @"Server=localhost\SQLEXPRESS;Database=AdventureWorks;Trusted_Connection=True;";
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = @"SELECT TOP (1) * FROM [AdventureWorks].[Sales].[CreditCard] WAITFOR DELAY '00:00:05'";
using (SqlDataReader reader = cmd.ExecuteReader())
{
var res = reader.Read();
return "Ok";
}
}
}
}
我正在使用 Fiddler 发送请求。 是 Fiddler 的问题(因为日志没问题),还是我在理解它的工作原理时遗漏了一些东西?
在 ASP .NET Core 中有很多在幕后执行的异步内容。 特别是,在执行控制器操作之前,线程必须读取和解析 fiddler 发送的 HTTP 请求。 在动作执行之后,需要另一个线程(可能是相同的)将响应写回给 fiddler。
那么在您的第一个案例中有 3 个请求时发生了什么:
reader.Read()
阻止。GetSyncDb()
,但尚未发送响应。因此,2 个请求在约 5 秒后结束,而第三个请求在约 10 秒后结束。
在 4 个请求的情况下:
reader.Read()
立即阻止。GetSyncDb()
,但尚未发送响应。因此,所有请求在约 10 秒后结束。 但当然它是随机的。 有时 ASP 可以捕获空闲线程并在它们被其他请求阻塞之前完成第一个响应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.