Как сделать параллельные HTTP-запросы - PullRequest
1 голос
/ 02 апреля 2011

У меня есть консольное приложение, которое делает один запрос к веб-странице и возвращает его статус сервера, например. 200, 404 и т. Д.

Я хотел бы применить следующие изменения:

Список пользовательских входов:

  • URL для запроса
  • Сколько параллельных соединений использовать (одновременных пользователей)
  • Сколько времени (в секундах) для отправки максимально возможного количества запросов

Список выходов:

  • Показать все выборки
  • Показывает выловов в секунду
  • Показать среднее время ответа (мс)

Я полагаю, что лучший способ сделать это - запустить несколько HTTP-выборок параллельно и запустить в одном процессе, чтобы он не перегружал клиентскую машину.

Мне действительно нравится C #, но я все еще новичок в этом. Я исследовал другие статьи на эту тему, но не до конца их понимаю, поэтому любая помощь будет принята с благодарностью.

Мой код:

static void Main(string[] args)
{
        try
        {
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://10.10.1.6/64k.html");
            webRequest.AllowAutoRedirect = false;
            HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
            //Returns "MovedPermanently", not 301 which is what I want.

            int i_goodResponse = (int)response.StatusCode;
            string s_goodResponse = response.StatusCode.ToString();
            Console.WriteLine("Normal Response: " + i_goodResponse + " " + s_goodResponse);
            Console.ReadLine();
        }
        catch (WebException we)
        {
            int i_badResponse = (int)((HttpWebResponse)we.Response).StatusCode;
            string s_badResponse = ((HttpWebResponse)we.Response).StatusCode.ToString();
            Console.WriteLine("Error Response: " + i_badResponse + " " + s_badResponse);
            Console.ReadLine();
        }
    }

Какой-то возможный код, который я нашел:

void StartWebRequest()
{
    HttpWebRequest webRequest = ...;
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}

void FinishWebRequest(IAsyncResult result)
{
    HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}

Ответы [ 2 ]

2 голосов
/ 02 апреля 2011

Это действительно хорошее место для использования параллельной библиотеки задач в .NET 4.0.Я завернул ваш код в блок Parallel.For, который будет выполнять несколько наборов запросов параллельно, сопоставлять общее время в каждой параллельной ветви, а затем вычислять общий результат.

int n = 16;
int reqs = 10;

var totalTimes = new long[n];

Parallel.For(0, n, i =>
    {
        for (int req = 0; req < reqs; req++)
        {
            Stopwatch w = new Stopwatch();
            try
            {
                w.Start();

                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://localhost:42838/Default.aspx");
                webRequest.AllowAutoRedirect = false;
                HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();

                w.Stop();
                totalTimes[i] += w.ElapsedMilliseconds;


                //Returns "MovedPermanently", not 301 which is what I want.            
                int i_goodResponse = (int)response.StatusCode;
                string s_goodResponse = response.StatusCode.ToString();
                Console.WriteLine("Normal Response: " + i_goodResponse + " " + s_goodResponse);
            }
            catch (WebException we)
            {
                w.Stop();
                totalTimes[i] += w.ElapsedMilliseconds;

                int i_badResponse = (int)((HttpWebResponse)we.Response).StatusCode;
                string s_badResponse = ((HttpWebResponse)we.Response).StatusCode.ToString();
                Console.WriteLine("Error Response: " + i_badResponse + " " + s_badResponse);
            }
        }
    });

var grandTotalTime = totalTimes.Sum();
var reqsPerSec = (double)(n * reqs * 1000) / (double)grandTotalTime;

Console.WriteLine("Requests per second: {0}", reqsPerSec);

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

Обратите внимание, что вы все равно должны быть здесь осторожны - мы не можем делить состояние, которое обновляется во время выполнения задач, между потоками, следовательно, массив для totalTimes, который объединяет итоги для каждой параллельной ветви и суммируется только всамый конец, когда параллельное выполнение завершено.Если мы этого не сделали, мы открыты для возможности состояния гонки - когда два отдельных потока пытаются обновить общее количество одновременно, потенциально искажая результат.

Я надеюсь, что это имеет смысл и полезноДля начала (здесь я вычисляю только запросы в секунду, остальные статистические данные добавить сравнительно легко).Добавьте комментарии, если вам нужны дальнейшие разъяснения.

0 голосов
/ 02 апреля 2011

Вы уже ответили на свой вопрос, вы можете использовать BeginGetResponse для запуска асинхронного запроса.

Другим, более удобным методом может быть использование класса WebClient, если вы более знакомы с событиями, чем с AsyncResult.

DownloadDataCompletedEventHandlerd

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...