Я создал образец приложения .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 в одном из комментариев, IIS как-то ограничивает или блокирует запросы.Когда я запустил свой WebApi как SelfHosted, он начал работать, как и ожидалось:
- Время выполнения метода "isresponsible" после большого количества запросов к методу ASYNC очень быстрое, около 0,02 сек .
- Время выполнения «ответственного» метода после большого количества запросов к методу SYNC очень медленное, около 35 сек .