2015-10-03 5 views
2

У меня есть настольное приложение C#, которому необходимо сделать несколько одновременных HTTP-запросов на один и тот же веб-сервер. Вот тест я провел, чтобы проверить, действительно ли мои запросы случаются одновременно:Несколько одновременных запросов к одному и тому же http-хосту

  1. На веб-сервере, создал тестовую страницу, которая спит в течение 3-х секунд (имитирует некоторые давно запущенной задачи), а затем возвращает текущую дату/время. Вот код (VB.Net):

    <% system.threading.thread.sleep (3000)%> <% =% в настоящее время>

  2. В C# приложение, у меня есть функция MakeRequest (), который использует System.Net.Http.HttpClient для создания веб-запроса и возвращает ответ как строку.

  3. Тогда в # приложение C есть функция вызывается нажатием кнопки, что вызывает MakeRequest() несколько раз асинхронно:

    вар ответы = подстерегающие Task.WhenAll (MakeRequest(), MakeRequest(), MakeRequest ());

В приведенном выше примере, MakeRequest() вызывается 3 раза. То, что я вижу на веб-сервере, когда я отслеживаю счетчик запросов/сек, состоит в том, что он получает 2 запроса, а затем через 3 секунды - еще один запрос. Это по дизайну, потому что значение по умолчанию для System.Net.ServicePointManager.DefaultConnectionLimit равно 2, поэтому мое приложение C# может отправлять только по 2 запроса одновременно, хотя я попросил 3. Общее время, когда приложение C# заняло завершение нажатия кнопки 6 сек.

Теперь в приложении C# я устанавливаю ServicePointManager.DefaultConnectionLimit = 1000000. На этот раз запросы/сек на веб-сервере показывают 3, а кнопка щелчка в приложении C# завершается через 3 секунды. Все хорошо до сих пор.

Далее я меняю приложение C# на 60 одновременных вызовов, а не на 3. Вот где вещи становятся интересными. Когда я нажимаю кнопку, я ожидаю увидеть запросы/сек на веб-сервере, чтобы увеличить до 60, а приложение C#, чтобы завершить нажатие кнопки за 3 секунды. То, что я получаю, это веб-сервер Requests/sec, показывающий что-то вроде 5, через 3 секунды еще 5 и т. Д. До тех пор, пока не будут сделаны все 60 запросов. Когда я снова нажимаю кнопку, то же изображение, за исключением Requests/sec spike, до 10 или 15, и щелчок кнопки, очевидно, завершается быстрее. Нажмите еще раз - на этот раз Запросы/сек показывают два всплеска до 30, а нажатие кнопки заканчивается через 6 секунд. Последующие нажатия кнопок приводят к появлению запросов/сек, начиная с 40 до 20 (всего 60 запросов), затем 50 и 10, затем, возможно, 55 и 5, и в конечном итоге мое приложение C# начинает отправлять все 60 запросов за один раз. Нажатие кнопки завершается за 3 секунды, а запросы/сек на веб-сервере показывают один всплеск до 60. Если я продолжаю нажимать кнопку, я последовательно получаю все 60 запросов одновременно.

Но это еще не все. Если я перестаю нажимать кнопку, мое приложение C#, похоже, «забудет» это предыдущее достижение. Я не перезапускаю приложение, просто перестаю нажимать кнопку на минуту, а при следующем нажатии я возвращаюсь к 5 запросам за раз, и описанный выше сценарий повторяется, если я продолжаю постоянно нажимать кнопку.

Я также выполнил вышеуказанный тест из MVC - только что скопировал и вставил код из приложения C# на страницу MVC. Получил точно такой же результат.

Может кто-нибудь объяснить, что происходит?Спасибо


Вот код приложения C#. Это приложение WinForms, а код живет внутри формы класса:

<!-- language: lang-c# --> 
private HttpClient _httpClient = new HttpClient(); 

private async void button1_Click(object sender, EventArgs e) 
{ 
    ServicePointManager.DefaultConnectionLimit = 1000000; 

    var sw = Stopwatch.StartNew(); 
    var responses = await Task.WhenAll(MakeRequest(), MakeRequest(), MakeRequest()); 
    sw.Stop(); 

    var msg = String.Join("\r\n", responses) + "\r\n\r\nTime Elapsed: " + sw.ElapsedMilliseconds; 
    MessageBox.Show(msg); 
} 

private async Task<string> MakeRequest() 
{ 
    using (var message = await _httpClient.GetAsync("http://TestServer/TestPage.aspx")) 
    { 
     return await message.Content.ReadAsStringAsync(); 
    } 
} 

ответ

1

две причины:

  1. клиента Windows, SKUs ограничить количество одновременных запросов IIS 10.
  2. Видимо, ваш клиент использует синхронный IO или в противном случае блокирует. Требуется некоторое время, чтобы получить пул потоков, нагретый. Нитки вводятся только со временем. Либо используйте async IO, либо неблокируйте, либо убедитесь, что потоки, которые вам нужны, на самом деле там. Что касается «забывания»: потоки пустых потоков с течением времени удаляются. Поэтому ваши тесты чувствительны к времени. Очень ненадежны, не вводите это в производство.
+0

Благодарим вас за ответ. 1. Да, я столкнулся с этой проблемой, поэтому переместил веб-страницу в IIS на Win Server 2008. На самом деле я попытался запустить страницу MVC, которая отправляет запросы на Server 2008 тоже - тот же результат, что и при запуске с Win 10 2. Не уверен, почему мой клиентский код будет синхронным. Я отправил код в исходный вопрос. Можете ли вы предложить, как мне его изменить? – Andrew

+0

Этот код в порядке. Можете ли вы отправить код, который выполняет 60 запросов одновременно? Пул потоков ASP.NET будет перегружен, кстати, со всеми этими синхронными ожиданиями. Используйте действие async mvc и используйте 'await Task.Delay'. – usr

+0

Код, который выполняет 60 запросов одновременно, совпадает с указанным выше, за исключением строки 'var response = await Task.WhenAll (MakeRequest(), MakeRequest(), MakeRequest());' вы повторяете 'MakeRequest() '60 раз. Что касается переполнения пула потоков ASP.Net, я не думаю, что это происходит, потому что когда мое клиентское приложение отправляет одновременно 60 запросов одновременно, веб-сервер успешно обрабатывает их все одновременно. Проверьте здесь: [link] (https://msdn.microsoft.com/en-us/library/ee377050 (v = bts.10) .aspx), раздел «Настройка ASP.NET 4 MaxConcurrentRequests для IIS 7.5/7.0 Интегрированный режим « – Andrew

Смежные вопросы