Время отклика UploadValuesAsync - PullRequest
       5

Время отклика UploadValuesAsync

1 голос
/ 03 ноября 2011

Я пишу тестовый жгут для проверки HTTP Post. Тестовый пример отправил бы 8 запросов http, используя UploadValuesAsync в классе веб-клиента с интервалом в 10 секунд. Спит 10 секунд после каждого 8 запроса. Я записываю время начала и окончания каждого запроса. Когда я вычисляю среднее время отклика. Я получаю около 800 мс. Но когда я запускаю этот тестовый пример синхронно, используя метод UploadValues ​​в веб-клиенте, я получаю среднее время ответа 250 миллисекунд. Можете ли вы сказать мне, почему разница между этими двумя методами? Я ожидал меньшее время отклика в Aync, но не получил этого.

Вот код, который отправляет 8 запросов асинхронно

                       var count = 0;
        foreach (var nameValueCollection in requestCollections)
        {
            count++;
            NameValueCollection collection = nameValueCollection;
            PostToURL(collection,uri);
            if (count % 8 == 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(10));
                count = 0;
            }
        }

ОБНОВЛЕНО Вот код, который отправляет 8 запросов SYNC

public void PostToURLSync(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
        {
            Response = "Not Started",
            Request = string.Join(";", collection.Cast<string>()
                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
            ApplicationId = collection["ApplicationId"]

        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                var responeByte = transportType2.UploadValues(uri, "POST", collection);
                response.EndTime = DateTime.Now;
                response.Response = Encoding.Default.GetString(responeByte);
            }

        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
        response.ResponseInMs = (int)response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        responses.Add(response);
        Console.WriteLine(response.ResponseInMs);
    }

Вот код, который отправляет HTTP URI

public void PostToURL(NameValueCollection collection,Uri uri)
    {
        var response = new ServiceResponse
                        {
                            Response = "Not Started",
                            Request = string.Join(";", collection.Cast<string>()
                                                        .Select(col => String.Concat(col, "=", collection[col])).ToArray()),
                            ApplicationId = collection["ApplicationId"]

                        };

        try
        {
            using (var transportType2 = new DerivedWebClient())
            {
                transportType2.Expect100Continue = false;
                transportType2.Timeout = TimeSpan.FromMilliseconds(2000);
                response.StartTime = DateTime.Now;
                transportType2.UploadValuesCompleted += new UploadValuesCompletedEventHandler(transportType2_UploadValuesCompleted);
                transportType2.UploadValuesAsync(uri, "POST", collection,response);
            }
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    }

Вот событие завершения загрузки

    private void transportType2_UploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e)
    {
        var now = DateTime.Now;
        var response = (ServiceResponse)e.UserState;
        response.EndTime = now;
        response.ResponseInMs = (int) response.EndTime.Subtract(response.StartTime).TotalMilliseconds;
        Console.WriteLine(response.ResponseInMs);

        if (e.Error != null)
        {
            response.Response = e.Error.ToString();
        }
        else
        if (e.Result != null && e.Result.Length > 0)
        {
            string downloadedData = Encoding.Default.GetString(e.Result);
            response.Response = downloadedData;
        }
        //Recording response in Global variable
        responses.Add(response);
    }

Ответы [ 2 ]

2 голосов
/ 20 ноября 2011

Одна проблема, с которой вы, вероятно, сталкиваетесь, заключается в том, что .NET по умолчанию будет ограничивать исходящие HTTP-соединения до предела (2 одновременных соединения на удаленный хост), которые предписаны соответствующим RFC. Предполагая 2 одновременных соединения и 250 мс на запрос, это означает, что время ответа для ваших первых 2 запросов будет 250 мс, второго 2 будет 500 мс, третьего 750 мс и последних 1000 мс. Это даст среднее время отклика 625 мс, что недалеко от 800 мс, которые вы видите.

Чтобы устранить удушение, увеличьте ServicePointManager.DefaultConnectionLimit до максимального числа одновременных соединений, которые вы хотите поддерживать, и вы должны увидеть, как среднее время отклика уменьшается.

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

Последняя проблема может быть вызвана методологией тестирования. Например, если ваш тестовый клиент имитирует сеанс браузера, сохраняя файлы cookie и повторно отправляя файлы cookie с каждым запросом, это может привести к проблемам с некоторыми серверами, которые будут сериализовать запросы от одного пользователя. Это часто упрощение для серверных приложений, поэтому им не придется иметь дело с блокировкой состояния перекрестных запросов, например, состояния сеанса. Если вы столкнулись с этой проблемой, убедитесь, что каждый WebClient отправляет разные файлы cookie для имитации разных пользователей.

Я не говорю, что вы сталкиваетесь со всеми этими тремя проблемами - возможно, вы сталкиваетесь только с 1 или 2 - но это наиболее вероятные виновники проблемы, с которой вы сталкиваетесь.

0 голосов
/ 12 января 2012

Как сказал Джастин, я пробовал ServicePointManager.DefaultConnectionLimit, но это не помогло решить проблему. Я не мог воспроизвести другие проблемы, предложенные Джастином. Я не уверен, как воспроизвести их в первую очередь.

То, что я сделал, я запустил тот же кусок кода на равноправной машине, который отлично работает время отклика, что я ожидал. Разница между двумя машинами заключается в операционных системах. Мой работает на Windows Server 2003, а другой компьютер работает на Windows Server 2008.

Поскольку он работал на других машинах, я подозреваю, что это может быть одной из проблем, указанных Джастином, или настроек сервера на 2003 или что-то еще. Я не потратил много времени после этого, чтобы выкопать этот вопрос. Поскольку это тестовая система, у нас был низкий приоритет по этому вопросу. Мы остановились без времени дальше.

Поскольку я не знаю, что именно это исправило, я не принимаю никаких ответов, кроме этого. По крайней мере, я знаю, что переход на сервер 2008 исправил эту проблему.

...