Много параллельных httpwebrequest через разные прокси. Как получить максимальную скорость?

Я пишу приложение для парсинга сайта букмекера. Итоговая цель - получать как можно чаще и быстрее свежую html сайта (в ней содержится нужная мне информация). Так как букмекер банит ip, если с него делать слишком много запросов к сайту, я пользуюсь коллекцией прокси (от 50 до 100 штук), чтобы распределить запросы между.

Язык программы - C#. Я использую асинхронные запросы (httpwebrequest) следующим образом:

ServicePointManager.DefaultConnectionLimit = 1000;
        ServicePointManager.Expect100Continue = false;
        ServicePointManager.UseNagleAlgorithm = false;

        for (var i = 0; i < proxyCollection.Count; i++)
        {
            var proxyLocal = proxyCollection[i];
            var iLocal = i;
            Task.Run(async () =>
                {
                    var httpWebRequest = (HttpWebRequest) WebRequest.Create(String.Format("https://bookmaker.com/page{0}", iLocal));
                    httpWebRequest.Proxy = proxyLocal;
                    httpWebRequest.PreAuthenticate = true;
                    httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

                    using (var httpWebResponse = (HttpWebResponse) await httpWebRequest.GetResponseAsync())
                    using (var responseStream = httpWebResponse.GetResponseStream())
                    using (var streamReader = new StreamReader(responseStream))
                    {
                        var stringContent = await streamReader.ReadToEndAsync();
                        //Тут я обрабатываю данные, которые получил с сайта. Обработка идет очень быстро - проблема не в ней
                        ProcessStringContent(stringContent);
                    }
                });            
         }

Все настройки, что я использую для ServicePointManager и для отдельного запроса я указал в коде.

Во-первых, почему-то все запросы не стартуют одновременно. Даже если посмотреть в диспетчер задач и нагрузку сети, то я наблюдаю два или больше пика запросов, между которыми может пройти до нескольких секунд молчания. Очевидно, что я никаких задержек не ставлю нигде и такое поведение странно. Также это поведение проявляется в том, что у меня есть несколько очень быстрых прокси, с которых запрос идет не больше 200мс, но если я запускаю все запросы одновременно, то частенько, по прошествию 5 секунд, запросы с быстрых прокси даже еще не начались.

Во-вторых, суммарное время выполнения всех запросов довольно велико. Наверняка, это связано с первой проблемой, но тем не менее, на это нужно тоже обратить внимание. Если я делаю запрос с каждой прокси по отдельности, синхронно, то наблюдаю время запроса 100-1000мс. Отсюда я ожидаю, что суммарное время всех запросов (100 штук), отправленных одновременно не должно превышать ну, скажем, 2 секунд. Ведь все они обрабатываются асинхронно!

В третьих, что больше всего странно - вышепоказанный код заставляет лагать интерфейс. У меня WPF приложение и я довольно хорошо знаком с понятием потока диспетчера и всем с этим связанным. И все равно у меня вызывает недоумение, почему код, вызванный в новом Task-е и при этом асинхронный может тормозить UI.
Есть только одна мысль, что синхронная операция WebRequest.Create может занимать какое-то время (об этом иногда пишут в интернете, мол для настройки использования прокси и для поиска dns требуется сколько то времени). И получается, что все потоки забиваются созданием запросов и это приводит к лагам. Можно ли как-то все это ускорить (убрать поиск настроек прокси, ускорить поиск днс) и избежать лагов?

Я перепробовал разные комбинации настроек ServicePointManager и не нашел победной.
Я ищу любой помощи в данном вопросе. Интересуют любые мнения по поводу, как правильно организовать в .Net решение нужной мне задачи? В интернете критически мало информации, может быть кто-нибудь поделится опытом? Ведь наверняка существуют решения для частого и быстрого сбора информации с различных сайтов поставщиков.

Заранее спасибо.
  • Вопрос задан
  • 1658 просмотров
Пригласить эксперта
Ответы на вопрос 1
AxisPod
@AxisPod
Т.е. вы сами загнали себя в рамки Task.Run и async/await, а затем спрашиваете почему же так. Task.Run не гарантирует запуск всего в отдельных потоках, на деле будет очередь и ThreadPool. А использование await в итоге выстраивает всё в очень малое кол-во потоков. Тут надо по старинке делать, старыми механизмами, будет более эффективно. BeginGetResponse/BeginGetRequestStream вам помогут и потоков много не потребуется.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы