C# - как выполнять несколько веб-запросов одновременно

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

мой код:

Parallel.ForEach(urls, new ParallelOptions {
  MaxDegreeOfParallelism = 10
}, s => {
  try {
    using(HttpRequest httpRequest = new HttpRequest()) {
      httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0";
      httpRequest.Cookies = new CookieDictionary(false);
      httpRequest.ConnectTimeout = 10000;
      httpRequest.ReadWriteTimeout = 10000;
      httpRequest.KeepAlive = true;
      httpRequest.IgnoreProtocolErrors = true;
      string check = httpRequest.Get(s + "'", null).ToString();
      if (errors.Any(new Func < string, bool > (check.Contains))) {
        Valid.Add(s);
        Console.WriteLine(s);
        File.WriteAllLines(Environment.CurrentDirectory + "/Good.txt", Valid);
      }
    }
  } catch {

  }
});

Кроме того, некоторые веб-серверы могут не обрабатывать ваши запросы параллельно (потому что это может выглядеть как DoS-атака или просто ограничивает количество подключений с IP-адреса). Тот факт, что вы делаете 10 параллельных запросов, не означает, что веб-сервер будет возвращать вам данные параллельно. Он по-прежнему может возвращать вам данные, как если бы вы отправили их, например, «Отправить запрос -> получить ответ -> отправить -> получить» и т. д.

KSib 14.09.2018 21:32

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

Rohit Ramname 14.09.2018 21:35

так как я могу сделать это быстрее? как другие инструменты делают это действительно быстро? даже инструменты, которые делают то же самое, что и я

Ariel 14.09.2018 21:40

@RohitRamname Сколько вычислительной мощности будет потреблять ожидающий для 10 HTTP GET? Дай угадаю: ноль?

Sir Rufo 14.09.2018 21:41

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

Rohit Ramname 14.09.2018 22:01

итак ... что я могу сделать, чтобы он работал быстрее?

Ariel 14.09.2018 22:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
6
20 480
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте сделать как показано ниже.

Parallel.ForEach(urls, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 }

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

Также обратите внимание на комментарий @KSib.

Спасибо за ответ, но с maxDegree = 10 он работал быстрее.

Ariel 14.09.2018 22:34
Ответ принят как подходящий

Маловероятно, что ваши служебные вызовы будут Привязанный к ЦП. Так что увеличение количества потоков для обработки нагрузки, возможно, не лучший подход - вы получите лучшую пропускную способность, если вместо этого будете использовать async и await, если сможете, используя более современный HttpClient вместо HttpRequest или HttpWebRequest.

Вот пример того, как это сделать:

var client = new HttpClient();

//Start with a list of URLs
var urls = new string[]
    {
        "http://www.google.com",
        "http://www.bing.com"
    };

//Start requests for all of them
var requests  = urls.Select
    (
        url => client.GetAsync(url)
    ).ToList();

//Wait for all the requests to finish
await Task.WhenAll(requests);

//Get the responses
var responses = requests.Select
    (
        task => task.Result
    );

foreach (var r in responses)
{
    // Extract the message body
    var s = await r.Content.ReadAsStringAsync();
    Console.WriteLine(s);
}

Спасибо попробую

Ariel 14.09.2018 22:49

Будет ли это работать и с запросами POST? Если да, то дайте мне знать, как это сделать, спасибо.

user5381191 16.12.2019 19:17

По какой-то причине я продолжал сталкиваться с запросом, сообщение уже отправлено, невозможно отправить повторно. Вместо string[] я создал List<HttpRequestMessage>, а затем var requests = httpRequestMessages.Select(h => Client.SendAsync(h))

user5381191 16.12.2019 20:24

Спасибо за ответ @john, у меня есть исключение сокета при использовании этого подхода System.IO.IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. Есть идеи?

Hamza Khanzada 16.04.2020 15:30

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

John Wu 16.04.2020 19:06

да, но как я могу справиться с этим в клиентском коде? если в случае, если сеть или целевой сервер не отвечает?

Hamza Khanzada 17.04.2020 07:04

@HamzaKhanzada Я не уверен, что понимаю вопрос. Как и в случае с любым исключением, вы catch и обрабатываете его любым способом, который диктуется вашими требованиями.

John Wu 17.04.2020 08:12

Будет ли этот подход работать с запросом POST? Я хочу отправить несколько файлов в API за один запрос. Я реализовал этот подход с помощью POST, но мой API не получает запрос.

Michael Brown 21.12.2020 21:36

@MichaelBrown Этот вопрос касается отправки нескольких запросов, а не отправки одного запроса с несколькими файлами (что значительно отличается). Предлагаю вам задать отдельный вопрос.

John Wu 22.12.2020 00:20

Другие вопросы по теме