Бенчмаркинг одновременных запросов ASP.NET к плохим результатам

У меня есть следующий код, который я сравниваю с jMeter и получаю около 3000 запросов в секунду на моей машине localhost (await отсутствует намеренно для запуска синхронно):

public async Task<HttpResponseMessage> Get()
{
    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new StringContent(Thread.CurrentThread.ManagedThreadId.ToString(), Encoding.UTF8, "text/plain");
    return resp;
}

Проблема заключается в том, что, когда я приостанавливаю запрос на одну секунду, как показано ниже, по какой-либо причине пропускная способность составляет до 10 запросов в секунду для каждого процесса w3wp.exe(снова await отсутствует намеренно запускается синхронно):

public async Task<HttpResponseMessage> Get()
    {
        Task.Delay(1000).Wait();
        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StringContent(Thread.CurrentThread.ManagedThreadId.ToString(), Encoding.UTF8, "text/plain");
        return resp;
    }

Даже когда я использую await, нет разницы, и 10 запросов в секунду вообще не улучшаются:

public async Task<HttpResponseMessage> Get()
{
    await Task.Delay(1000);
    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new StringContent(Thread.CurrentThread.ManagedThreadId.ToString(), Encoding.UTF8, "text/plain");
    return resp;
}

Я пробовал все настройки конфигурации и ничего не менял вообще: `

web.config

  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="65400" />
    </connectionManagement>
  </system.net>

Aspnet.config

  <system.web>
    <applicationPool 
        maxConcurrentThreadsPerCPU="100" />
  </system.web>

machine.config

 <processModel
 autoConfig="false"
 memoryLimit="70"
 maxWorkerThreads="100"
 maxIoThreads="100" />

Конфигурации установлены как для x86, так и для x64

У меня есть 32 гигабайта mem и 4 физических ядра, Windows 10.

Процессор не переходит на 10% нагрузку при сканировании 10 запросов в секунду.

В приведенном выше коде используется WEB API, но, конечно, я воспроизвожу те же результаты с помощью обработчика HTTP.

Ответ 1

Здесь возможно понимание. Во всяком случае, исследовать.

Task.Delay() создает новую задачу, задача которой заключается в приостановке. Если я правильно понимаю, задачи часто отправляются в рабочий пул .Net, который имеет ограниченный размер. (Вы можете проверить с помощью ThreadPool.GetMaxThreads). Когда вы пытаетесь ввести слишком много, код будет "резервным", поскольку он ждет пула потоков иметь пространство.

Итак, скажем, у вас есть пул потоков размером 40. После того, как вы отправили 40 заданий, все ждут секунды, вы максимально удаляете пул потоков. Вашим узким местом будут задачи, забивающие пул потоков, не уступая место.

Как правило, задачи, которые выполняют дорогостоящие запросы на ввод-вывод IO или файлы ввода-вывода IO, в то время как они ждут выполнения работы. Интересно, что Task.Delay более "цепляется".

Попробуйте заменить Task.Delay() для System.Threading.Thread.Sleep() и посмотреть, не изменилось ли это.

Ответ 2

Я знаю, что для Windows 8 существует ограничение максимального количества одновременных подключений 10, чтобы остановить людей, пытающихся использовать потребительскую ОС для выполнения рабочих нагрузок сервера. Я не вижу причин, по которым Windows 10 будет отличаться.

http://blogs.iis.net/owscott/windows-8-iis-8-concurrent-requests-limit