Загрузка картинок System.Threading.Tasks.Parallel.For и ForEach

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Привет, комрады. Есть пару вопросов по параллельным запросам.
Есть список, без файла, куда мы раннее напарсили ссылок на картинки.
Код в цикле хорошо сохранял изображения, но последовательно. Называя их по счетчику от 1 и... пока не надоест. Так сотню изображений сохраняет минут 3-5.
Картинки грузятся с разных сайтов, никаких лимитов на запросы выходит что нет, не долго думая решил замутить System.Threading.Tasks.Parallel.ForEach , спасибо Третьему конкурсу статей и LexxWork
Код:
int count = 1;
var list = project.Lists["Image"].ToList();
 
  System.Threading.Tasks.Parallel.ForEach(list, p => {
  var pic = project.Lists["Image"];
  project.Variables["IMAGE_TEMP_SAVE_VAR"].Value = pic[0];
  pic.RemoveAt(0);

//Парсим расширение картинки
  var type ="";
  type = Regex.Match(project.Variables["IMAGE_TEMP_SAVE_VAR"].Value, "\\.[a-z]{2,5}$").Value;
//Если картинка без расширения, ставим своё
  if (type == "" )
  {
  type = ".jpg";
  }
 
//Сохраняем картинку, в этом страхе просто URL  и место сохранения
ZennoPoster.ImageProcessingUntreatedFromUrl(project.Variables["IMAGE_TEMP_SAVE_VAR"].Value, project.Directory+"\\Images\\"+project.Variables["IMAGE_KEYWORD_LAT"].Value + "\\"+  count + type);
//Увеличиваем счетчик
  count++; 
  }
  );
Код индусский, может и хуже, делал для теста. Скорее всего все вообще не верно

~Первый вопрос вообще банальный, да и ошибка очевидна — при параллельном скачивании как организовать счетчик, чтоб на выходе получить имена картинок 1,2,3... ? Только рандомные имена выйдет сделать?

~Я так понимаю, этот ForEach грузит все что в списке одновременно? А чтоб, допустим, загружать в 50 threadов, не разбивая на подсписки — нужно использовать "Parallel.For"?
 
  • Спасибо
Реакции: Karamzin

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Сделал с рандомными названиями и через Parallel.For, но все равно грузит последовательно, хоть указал Parallel.For(0,50.........) . Лыжи не едут, или я:ce:
 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
Код:
for (int i=0; i<50; i++)
new Thread(delegate() {
             project.SendInfoToLog(Thread.CurrentThread.ManagedThreadId.ToString());
            }
    ).Start();
 
  • Спасибо
Реакции: Nord и Dimionix

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Код:
for (int i=0; i<50; i++)
new Thread(delegate() {
             project.SendInfoToLog(Thread.CurrentThread.ManagedThreadId.ToString());
            }
    ).Start();
Это оно одновременно вернуло в лог айдишники всех потоков?
Мне нужно одновременно с конструкцией For(Int32, Int32, Action<Int32>) использовать обычный цикл?
Пытаюсь разобрать в этом, пока знаний не хватает одолеть.
Ткните носом в каком направлении идти, желательно поконкретней направление :-):ah:
 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
Это оно одновременно вернуло в лог айдишники всех потоков?
Оно оно
Ткните носом в каком направлении идти, желательно поконкретней направление
Ну так вместо вывода айдишников воткни код загрузки картинок.. по моему яснее ясного)
Банально запустятся энное кол-во потоков для загрузки.. Всем этим новомодным паралелфорам я не верю, а в потоках уверен)
 
  • Спасибо
Реакции: Nord

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Оно оно

Ну так вместо вывода айдишников воткни код загрузки картинок.. по моему яснее ясного)
Банально запустятся энное кол-во потоков для загрузки.. Всем этим новомодным паралелфорам я не верю, а в потоках уверен)
Вроде получилось, но криво. Зенка вылетает через пару минут работы.
И картинки постоянно перезаписываются, хотя я указал "i" как имя сохраняемого файла. А они, например, файл с именем "6" перезаписывает 5-6 раз

Код:
    project.SendInfoToLog("","Начинаем скачивать изображения",true);
//        int a = 0;
//        int b = 20;
//     
        while(project.Lists["Image"].Count > 0)
                 
                        {
//                            for (int i=a; i<b; i++)    new Thread(delegate() {
                            for (int i=0; i<50; i++)    new Thread(delegate() {
                                                                            //Берем ссылку на картинку и удаляем
                                                                            var pic = project.Lists["Image"];
                                                                            string temp = pic[0];
                                                                            pic.RemoveAt(0);

                                                                            //Парсим разрешение картинки
                                                                            var type_f ="";
                                                                                type_f = Regex.Match(temp, "\\.[a-z]{2,5}$").Value;
                                                                             
                                                                                if (type_f == "" )
                                                                                    {
                                                                                        type_f = ".jpg";
                                                                                    }
                                                                     

                                                                                //Сохраняем
                                                                                ZennoPoster.ImageProcessingUntreatedFromUrl(temp, project.Directory+"\\Images\\"+project.Variables["IMAGE_KEYWORD"].Value + "\\"+  i + type_f);
                                         
                                                                            }).Start();
//                            a = a + 20;
//                            b = b + 20;
                        }
                         
                project.SendInfoToLog("","Скрипт выполнен ",true);


Update
Аааа, это оно от While перезаписывает, потому что по кругу от 0 до 50 пускает
 

Вложения

Последнее редактирование:

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
Как-то так..

В общем коде функция принимающая параметры директории куда качать, урл, числовой номер (сейчас берется колво оставшихся элементов списка), и кейворд. Эта фунция вызывается в отдельном потоке. Сделано некое подобие пула, т.е указываем в переменной THREAD_BASE_COUNT кол-во потоков которые должны одновременно работать, а то система подавится. Удачные скачивания в лог не пишет, чтоб не спамить.. ошибки - пишет. И постоянно спамит кол-вом запущенных рабочих потоков.
 

Вложения

  • 111,7 КБ Просмотры: 39
  • Спасибо
Реакции: Nord

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
  • Спасибо
Реакции: DmitryAk

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
А можно как то увеличить время жизни потока?
А то они не успевают скачать изображение, при хреновом соединении и большом размере, а потом через определенно время после запуска(1-2 минуты, не засекал) обрывают загрузку.

 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
А можно как то увеличить время жизни потока?
Это не время жизни потока срывается, а таймаут вебклиента срабатывает. Его увеличить не выйдет. Если очень прям нужно можно на вебреквест переписать, но там уж одной строкой не выйдет))
 
  • Спасибо
Реакции: Nord

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Это не время жизни потока срывается, а таймаут вебклиента срабатывает. Его увеличить не выйдет. Если очень прям нужно можно на вебреквест переписать, но там уж одной строкой не выйдет))
Поэксперементирую с количеством потоков тогда =)
Либо при неуспехе передать УРЛ назад в список...
 

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
Поэксперементирую с количеством потоков тогда =)
Либо при неуспехе передать УРЛ назад в список...
А сколько запускаешь потоков то кстати?) Т.к. слишком большое кол-во бессмысленно.. толку что они будут качаться параллельно, если по времени это будет дольше...
 

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Тестил на 50, 100 и 150. На 150 - 43% файлов в итоге скачивает. Секунд за 45 1к файлов( остальные, потяжелее, подкачивались или обрывались за след пару минут). На 50 - 65%. Минуты за 3 1к файлов. После обрыва удаляет все недокачанные из папки само.
В один поток 1к скачивало за 45 минут, 99% успеха =)
Сейчас погоняю на 25 и 10


ПС
Еще, про время - цикл отрабатывает, шаблон уже выполнен, можно начинать сначала.
А изображения еще не загружены. Через пару минут в лог начинают ссыпаться ошибки =)
То есть шаб уже выполнен, кнопки записи и действий разморозились, а ошибки начинают сыпаться в лог(ну, тогда, когда потоки обрываются ). Такая вот необычная бугагашенька :D
 
Последнее редактирование:

DmitryAk

Client
Регистрация
14.12.2016
Сообщения
860
Благодарностей
824
Баллы
93
Такая вот необычная бугагашенька
Это нормально, так и должно быть) Потоки то на фоне работают.. Можно конечно добавить в самый конец сниппета еще такой блок , чтоб шаб не завершался пока все не скачает:
Код:
while (CommonCode.ThreadCount>0){
         if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return null; // Прерывание в ZP
         if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return null; // Прерывание в PM     
         Thread.Sleep(200);
}
project.SendInfoToLog("","Скрипт выполнен ",true);
 
  • Спасибо
Реакции: Nord

Nord

Client
Регистрация
22.03.2012
Сообщения
2 406
Благодарностей
1 473
Баллы
113
Это нормально, так и должно быть) Потоки то на фоне работают.. Можно конечно добавить в самый конец сниппета еще такой блок , чтоб шаб не завершался пока все не скачает:
Код:
while (CommonCode.ThreadCount>0){
         if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return null; // Прерывание в ZP
         if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return null; // Прерывание в PM    
         Thread.Sleep(200);
}
project.SendInfoToLog("","Скрипт выполнен ",true);
Спасибо, попробую, когда оно докачает. Наверное, уже утром :-)
 

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