Параллельные запросы

doc

Client
Регистрация
30.03.2012
Сообщения
8 605
Благодарностей
4 596
Баллы
113
тогда пару зенобоксов лучше, в РМ править и в бокс заливать, например у меня 10 боксов с пустыми проектами прикупить )))))) будет у тя 10 боксов по 20 потоков и гоняй потом, насчёт 10 шучу и на счёт себя тоже, но так же почти шутка, но в каждой шутке, как говорится.....
с лайта бокс выйдет однопоточный
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 379
Благодарностей
2 039
Баллы
113

Vasyl1

Client
Регистрация
11.12.2016
Сообщения
194
Благодарностей
20
Баллы
18
Привет. Решил данную задачу? Просто у мне нужно похожое и никак не могу реализовать! Помоги. Ссылка
Сижу изучаю "параллельные запросы", очень интересная тема.
Шлю лучи благодарности, отдал свой голос за статью ещё на старте голосования.

У меня вот только затыки, не понимаю, как реализовать: отправлять 3 GET запроса (параллельно) и получать ответ (содержание) в 3 разные переменные.
Никак через данный метод это сделать нельзя или вообще нельзя это сделать?
Помоги LexxWork, интересует решение вопроса, тот что в самом верху от ibred.
Привет вам, дорогие форумчане!
Как и в предыдущей статье я буду рассказывать о том что интересно мне и в итоге попытаюсь заинтересовать и Вас!

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

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

Иногда так бывает, что перед шаблоном стоит задача просто получать данные с интернет-ресурсов, а потом что-то с ними делать. Очень часто эти задачи однотипные и в основном повторяются если не в цикле то в многопотоке шаблона.
Допустим, мне нужно собрать данные с определенного сайта, перебирая страницы с 1 по N. Обязательным условием должна быть возможность не использовать браузер и это очень важно. Обычная логика будет завернуть запрос и обработку в цикл и подкорректировать логику для возможности работы шаблона в многопотоке, если страниц много.
В принципе это нормально, но я нашел альтернативное решение с использованием параллельных циклов C# Parallel.For и Parallel.ForEach.

Теперь я постараюсь описать работу одного из трех шаблонов, которые будут в приложении. Перед нами стоит задача «выпарсить» весь список сайтов по домену высшего уровня с сайта domaintyper.com.
Для начала нам нужно подготовить данные, которые мы будем использовать для параллельного цикла.


int threads = int.Parse(project.Variables["threads"].Value);
var proxy = project.Variables["proxy"].Value;
string url = project.Variables["url"].Value;
var path = project.Variables["path"].Value;
int start_page = int.Parse(project.Variables["start_page"].Value);
project.Variables[
"start_page"].Value = (start_page + threads).ToString();
var regex = new System.Text.RegularExpressions.Regex("(?<=<tr\\sclass=\"wsTR[^<]*?<td>[^<]*?</td>[^<]*?<td>)[^<]+");
List<
int> emptypages = new List<int>();
List<
string> rlist = new List<string>();
int lastpage = 0;
int extracted = 0;

threads – отвечает у нас за количество «потоков», то есть сколько параллельных запросов мы собираемся сделать за раз.
proxy – адрес прокси если вдруг кому захочется поэкспериментировать. Сразу же говорю, скорость будет относительно медленней, так как данный пример не предусматривает использования уникальных прокси для каждого запроса в отдельности, но в принципе это возможно.
url - является корневой ссылкой, его значение можете увидеть открыв шаблон.
path отвечает за путь к файлу куда мы будем дописывать список
start_page – номер страницы с которой мы будем продолжать скачивать.
List<int> emptypages будет собирать те номера страниц где не удалось по какой-то причине обнаружить нужные нам строки.
List<string> rlist – главный список, в который мы будем складывать все найденные на странице сайты.
lastpage будет сигнализировать о том что мы дошли до последней страницы и дальше делать запросы не нужно.
extracted покажет сколько мы нашли ссылок на странице
А вот и сам параллельный цикл.


System.Threading.Tasks.Parallel.For(start_page, start_page+threads, p => {

___var response = ZennoPoster.HttpGet(url: url+p.ToString(), proxy: proxy, Encoding:"UTF-8", Timeout: 60000);
___List<string> domains = regex.Matches(response).Cast<System.Text.RegularExpressions.Match>().Select(s=>s.Value).Where(s=>s!="").ToList();
___project.SendInfoToLog(domains.Count.ToString(), p.ToString());
___rlist.AddRange(domains);
___extracted += domains.Count;
___if(response.Contains("<div class=\"pagingDivDisabled\">Next</div>")){
______emptypages.Add(p);
______if(domains.Count > 0){
_________lastpage = p;
_________project.SendInfoToLog("lastpage", p.ToString());
______}
___}
___else{
______if(domains.Count <= 0)
_________emptypages.Add(p);
___}
});

Метод Parallel.For работает как обычный цикл от start_page до start_page+threads только метод, который передается третьим параметром будет выполняться параллельно для каждого итератора p.
В этом методе производится запрос по адресу
url+p , вытаскиваются из ответа данные в список domains , а уже только после добавляем domains в результирующий - rlist.AddRange(domains) . Дальше идет определение, является ли наша страница последней и если нет, плюс добавляем в emptypages номер страницы, которая неудачно подгрузилась.
Завершение работы
Parallel.ForEach означает что мы скачали все страницы, обработали их, собрали все что можно в результирующие списки rlist и emptypages.
Все, что идет ниже параллельного цикла, это анализ, сохранение, логирование и вызов исключения в случае если
emptypages хранит в себе не ту страницу которую стоило ожидать последней на сайте.
В итоге мы получаем отдельный сниппет, который собирает для нас данные в параллельном режиме в один поток зеннопостера.
Два других шаблона работают по тому же принципу, но выполняют другие задачи.
ahrefs.com(top_domains).xmlz – может работать со списком прокси. Рекомендуемое число потоков от 50 до 1000;
gplusparser2.xmlz – скачивает аватарки на диск по ссылкам из уже подготовленного списка. Ставьте смело 10 000 потоков и смотрите что получится.

Вот и все. Удачи всем и спасибо за внимание!
 

barkasian

Client
Регистрация
03.12.2014
Сообщения
127
Благодарностей
137
Баллы
43
Приветствую! Подскажите по работе с параллельными потоками, - как в случае логического false остановить один поток из множества?
В практическом руководстве microsoft (пруф.) предлагается методом Stop прекратить ВЕСЬ цикл Parallel.For
 

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
823
Баллы
93
как в случае логического false остановить один поток из множества?
return.
Будет выход из одной итерации, т.к по сути одна итерация в Parallel.For это метод, а выход из метода это return.
 
  • Спасибо
Реакции: barkasian

barkasian

Client
Регистрация
03.12.2014
Сообщения
127
Благодарностей
137
Баллы
43
Вот еще вопрос, во время работы Parallel.For возникает ошибка в логе вида:

Выполнение действия csharp owncode Произошла одна или несколько ошибок

Пропускал код через обычный цикл For - данной ошибки не возникало. Куда копать?
 

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
823
Баллы
93
Ну тут вариантов может быть масса. Возможно идет доступ к каким то ресурсам без блокировки.
Т.к в ownCode отладки как таковой нет, то придется попотеть чтобы найти баг.

Как вариант, пробрасываем в метод в ownCode переменную project.
Это чтобы можно было в лог мессаги выводить типа project.SendInfoToLog("...");
Потом просто в разных местах втыкаем что то типа этого project.SendInfoToLog("--1--"); project.SendInfoToLog("--2--"); и т.д.

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

Костыльно? Криво? Да.
Но по другому х.з. как отдебажить, чтобы сильно не заморачиваться.
Если кто подскажет как красивее и проще сделать, с удовольствием послушаю.))
Кстати такой метод был единственным вариантом, пока в кубиках C# не добавили бряки, и не появилась норм возможность дебажить код.

Ну а лучший вариант, это все в VS отлаживать, и потом переносить в зенку. Я так делаю.
Но это не всегда удобно.
 
  • Спасибо
Реакции: barkasian

barkasian

Client
Регистрация
03.12.2014
Сообщения
127
Благодарностей
137
Баллы
43
@Moadip, благодарю за наводку. Допер, суть была в том, что у всех потоков был доступ к одному файлу на диске, куда записывались данные. После блокировки кодом
Код:
  lock(SyncObjects.ListSyncer)
    {
        ...
    }
ошибка перестала выскакивать.
 
  • Спасибо
Реакции: bedl0

Moadip

Client
Регистрация
26.09.2015
Сообщения
509
Благодарностей
823
Баллы
93
суть была в том, что у всех потоков был доступ к одному файлу на диске, куда записывались данные.
Тогда надо смотреть, есть ли там смысл в Parallel.For.
Если у тебя логика не особо ресурсозатратная, которая идет до записи в файл, то смысла особо нет в Parallel.For, по скорости много не выиграешь.
 

burhanov88

Client
Регистрация
08.04.2015
Сообщения
69
Благодарностей
23
Баллы
8
Кто может подсказать как можно при помощи данного метода можно выполнить следующую задачу: Берём элемент url из списка выполняем get запрос, данные полученные из Гет запроса проводим регуляркой и записываем в список.
Кто может помочь?
 

irving zisman

Client
Регистрация
18.05.2017
Сообщения
225
Благодарностей
28
Баллы
28
А если в запросе нужно еще и куки отправить, как их туда прописать????
 

SergeiKo

Новичок
Регистрация
02.10.2018
Сообщения
9
Благодарностей
0
Баллы
1
Офигенно) А хотелось бы оптимизировать или уже пофиг?
А ты возьмешься за оплату за доработку этого метода ? Нужно чуть расширить функционал... Как с тобой можно связаться ?
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)