【发布时间】:2019-01-24 12:07:35
【问题描述】:
我创建了示例 .NET Core WebApi 应用程序来测试异步方法如何提高吞吐量。应用托管在 IIS 10 上。
这是我的控制器的代码:
[HttpGet("sync")]
public IEnumerable<string> Get()
{
return this.GetValues().Result;
}
[HttpGet("async")]
public async Task<IEnumerable<string>> GetAsync()
{
return await this.GetValues();
}
[HttpGet("isresponding")]
public Task<bool> IsResponding()
{
return Task.FromResult(true);
}
private async Task<IEnumerable<string>> GetValues()
{
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
return new string[] { "value1", "value2" };
}
有一些方法:
Get() - 同步获取结果
GetAsync() - 异步获取结果。
IsResponding() - 检查服务器是否可以处理请求
然后我创建了示例控制台应用程序,它创建了 100 个控制器的同步请求和异步方法(不等待结果)。然后我调用方法IsResponding() 来检查服务器是否可用。
控制台应用代码是:
using (var httpClient = new HttpClient())
{
var methodUrl = $"http://localhost:50001/api/values/{apiMethod}";
Console.WriteLine($"Executing {methodUrl}");
//var result1 = httpClient.GetAsync($"http://localhost:50001/api/values/{apiMethod}").Result.Content.ReadAsStringAsync().Result;
Parallel.For(0, 100, ((i, state) =>
{
httpClient.GetAsync(methodUrl);
}));
var sw = Stopwatch.StartNew();
var isAlive = httpClient.GetAsync($"http://localhost:50001/api/values/isresponding").Result.Content;
Console.WriteLine($"{sw.Elapsed.TotalSeconds} sec.");
Console.ReadKey();
}
其中{apiMethod} 是“同步”或“异步”,具体取决于用户输入。
在这两种情况下,服务器都长时间没有响应(大约 40 秒)。 我解释说,在异步情况下,服务器应该继续快速服务请求,但事实并非如此。
更新 1: 我已经像这样更改了客户端代码:
Parallel.For(0, 10000, ((i, state) =>
{
var httpClient = new HttpClient();
httpClient.GetAsync($"http://localhost:50001/api/values/{apiMethod}");
}));
using (var httpClient = new HttpClient())
{
var sw = Stopwatch.StartNew();
// this method should evaluate fast when we called async version and should evaluate slowly when we called sync method (due to busy threads ThreadPool)
var isAlive = httpClient.GetAsync($"http://localhost:50001/api/values/isresponding").Result.Content;
Console.WriteLine($"{sw.Elapsed.TotalSeconds} sec.");
}
并调用IsResponding()方法执行了很长时间。
更新 2 是的,我知道异步方法是如何工作的。是的,我知道如何使用 HttpClient。这只是一个证明理论的样本。
更新 3 正如 StuartLC 在其中一个 cmets 中提到的,IIS 以某种方式限制或阻止请求。当我以 SelfHosted 身份启动 WebApi 时,它开始按预期工作:
- 在向 ASYNC 方法发出一堆请求后,“isresponsible”方法的执行时间非常快,约为 0.02 秒。
- 在向 SYNC 方法发出一堆请求后,“isresponsible”方法的执行时间非常慢,大约为 35 秒。
【问题讨论】:
-
httpClient.GetAsync(url).Result.Result 让它在那里等待响应。 Asnyc 只是意味着它不会阻塞线程,这非常适合调用事物而不阻塞 UI(例如),但并不意味着它会转到下一行代码并继续运行。如果您想发出多个请求然后继续,那么您需要为每个请求创建一个线程。 -
ASP.NET Core 没有 SynchronizationContext...获取此链接了解大多数信息...blog.stephencleary.com/2017/03/…
-
也许问题出在客户端?在发出请求之前尝试在客户端使用
System.Net.ServicePointManager.DefaultConnectionLimit = 100; System.Net.ServicePointManager.Expect100Continue = false; System.Net.ServicePointManager.UseNagleAlgorithm = true;。 -
@Archer 这就是我想要的 - 等待服务器响应并测量响应时间。首先,我使用请求长时间运行的方法对我的服务器进行 DDOS,然后检查它将如何为其他请求提供服务
标签: c# async-await asp.net-core-webapi