Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.08.2016, 21:39   #1
nibufep
Форумчанин
 
Регистрация: 02.08.2014
Сообщений: 476
По умолчанию Дождаться завершения всех потоков

Доброго времени суток!
Имеется проблема, не могу придумать решение, вот в чем суть:

имеется несколько потоков, 5 штук допустим, в каждом потоке собираются ссылки, и количество этих ссылок всегда разное, собираются они ругулярками, потом в цикле с каждой такой ссылкой запускается еще один поток и парсит со страницы цифры, вот нужно сначала спарсить цифры с каждой страницы, а потом их все сложить, в голову только приходит объявить глобальную переменную (и даже не одну, так как основных потоков как мы помним у нас 5) и в каждом потоке её увеличивать, но опять же как потом это все сложить, как узнать какой поток последний соберет эти цифры, и вообще идея с глобальной переменной мне не очень нравится, может кто подскажет как решить эту проблему?
nibufep вне форума Ответить с цитированием
Старый 23.08.2016, 22:43   #2
come-on
Участник клуба
 
Регистрация: 21.10.2015
Сообщений: 1,361
По умолчанию

пул потоков
come-on вне форума Ответить с цитированием
Старый 23.08.2016, 22:48   #3
nibufep
Форумчанин
 
Регистрация: 02.08.2014
Сообщений: 476
По умолчанию

Цитата:
Сообщение от come-on Посмотреть сообщение
пул потоков
Можно поподробней?
nibufep вне форума Ответить с цитированием
Старый 23.08.2016, 22:54   #4
come-on
Участник клуба
 
Регистрация: 21.10.2015
Сообщений: 1,361
По умолчанию

вы бы хоть написали какая делфи у вас, а то есть большая разница
come-on вне форума Ответить с цитированием
Старый 24.08.2016, 00:44   #5
nibufep
Форумчанин
 
Регистрация: 02.08.2014
Сообщений: 476
По умолчанию

Цитата:
Сообщение от come-on Посмотреть сообщение
вы бы хоть написали какая делфи у вас, а то есть большая разница
XE10
nibufep вне форума Ответить с цитированием
Старый 24.08.2016, 18:16   #6
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

А чем не устраивает глобальная переменная? То, что глобальные переменные - зло в эпоху мультипотоков, так это для внутренней структуры. А для совместной работы потоков без этого порой никуда. Этот форум тому пример, в одну эту тему (глоб переменная) отписались разные пользователи (потоки) и ничего, форум не рухнул )) Главное синхронизировать.

Пусть в классе формы есть некий счётчик (переменная с именем ThisGlobalVar_Warning_Warning), который потоки увеличивают через методы синхронизации (операция изменения счётчика относительна быстра по отношению к вэб-серфингу и парсингу и не повлияет на визуализацию, скорость работы потоков). Этот метод прост, быстр (в плане кода по крайней мере) и суров.

Если не устраивает такой подход, то есть несколько других вариантов - сообщения или сигналы, например. Пусть форма ждёт какого-нибудь, например, SendMessag'а и при получении увеличивает счётчик. Хотя, и тут переменную лучше объявлять глобальной для класса формы, иначе впоследствии прочитать её можно будет только с компонента на который вывелась инфа (или через какую-нибудь функцию/механизм и т.п.), а напрямую не получится.

Цитата:
приходит объявить глобальную переменную (и даже не одну, так как основных потоков как мы помним у нас 5)
А зачем 5? Пусть сразу всё в одну переменную складывается, всё равно же конечный результат нужен. Даже если и не конечный результат нужен, то можно вместо 5 переменных один массив на них завести.

А вот если бы задача стояла другая - например, обрабатывать бОльшие объёмы данных, то идея с глобальной переменной была бы уже не такой хорошей.
eoln вне форума Ответить с цитированием
Старый 24.08.2016, 19:03   #7
nibufep
Форумчанин
 
Регистрация: 02.08.2014
Сообщений: 476
По умолчанию

Цитата:
Сообщение от eoln Посмотреть сообщение
А чем не устраивает глобальная переменная? То, что глобальные переменные - зло в эпоху мультипотоков, так это для внутренней структуры. А для совместной работы потоков без этого порой никуда. Этот форум тому пример, в одну эту тему (глоб переменная) отписались разные пользователи (потоки) и ничего, форум не рухнул )) Главное синхронизировать.
да я не сказать что прям против глобальных переменных, но вопрос такой был
Цитата:
но опять же как потом это все сложить, как узнать какой поток последний соберет эти цифры
Цитата:
Сообщение от eoln Посмотреть сообщение
А зачем 5?
Потому что это не относящие друг к другу данные, и их нужно отдельно считать / выводить.
nibufep вне форума Ответить с цитированием
Старый 24.08.2016, 19:53   #8
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Тут вариантов куча.
1) Смотри потоко безопасную очередь. Признаком конца является пустая очередь.
2) Делать боса который будет распределять задачи по свободным потокам. Переодически проверяет свободны потоки или нет.
3) Делать диспетчера. Потоки посылают сообщения. Диспетчер быстро нагружает рабочего и засыпает. Сообщения всегда синхронны.

Как обойтись без глобальной переменной? Вот пример, чуть до делать и будет пункт 2.
Бос ждет пока все потоки рабочих не завершаться.
Код:
procedure TBoss.Execute;
var
 i:Integer;
 cmd:TWokerCMD;
begin
 // while not Terminated do
     begin
       for i:=1 to Length(Fabrick.Woker)-1 do
          begin
           cmd:=TSumData.Create;
           TSumData(cmd).Data:=TSumData(TasksList[0]).Data;
           TSumData(cmd).Count:=TSumData(TasksList[0]).Count;

           cmd.Count:=cmd.Count div Length(Fabrick.Woker);
           Fabrick.Woker[i].SendCommand(cmd);
          end;
 //          Fabrick.Woker[i].Resume;
   //    Fabrick.Woker[1].SendCommand(TasksList[0]);
     //  Fabrick.Woker[2].SendCommand(TasksList[1]);

       for i:=1 to Length(Fabrick.Woker)-1 do
           Fabrick.Woker[i].Resume;

       for i:=1 to Length(Fabrick.Woker)-1 do
           Fabrick.Woker[i].WaitFor;
       Sleep(10); //
     end;
  ReturnValue:=idOK;
end;

{ TWoker }

procedure TWoker.Execute;
begin
 if Task<>nil then
    Task.Exec;
  ReturnValue:=idOk;
end;
WaitFor работает в связке с ReturnValue.

Пул потоков? Это да можно и его использовать.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 24.08.2016, 20:09   #9
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Цитата:
но опять же как потом это все сложить, как узнать какой поток последний соберет эти цифры
Нужна инфа прям по тому потоку (из 5-ти первородных), который отработал последним? Или достаточно подождать завершения 5 потоков + его дочек, внучек, правнучек, праправучек, прапраправнучек и других далёких потомков?

Для любого из этих вариантов можно вести учёт потоков (легко организовать свой так называемый пул через TThreadList). При создании потока, пусть он добавляется в один из пяти TThreadList, смотря кто был его прародителем (TThreadList может быть глобальной переменной, кстати, не требующей ручной синхронизации), а по завершению удаляет себя от туда.
Тогда мы всегда будем знать пуст ли каждый из 5-ти списков потоков или нет. Только в TThreadList нужна сначала добавить потомка, а потом уже удалять родителя, иначе, пусть даже на доли секунды, TThreadList может оказаться пустым, что может посчитаться как завершение всех потоков
eoln вне форума Ответить с цитированием
Старый 24.08.2016, 21:02   #10
nibufep
Форумчанин
 
Регистрация: 02.08.2014
Сообщений: 476
По умолчанию

Смотрите вообщем какая задача, постараюсь более подробно объяснить, у меня есть 4 listview, в каждый должны будут вывестись данные, есть так же 4 потока / 4 основных ссылки, 4 абсолютно одинаковых потока, я запускаю каждый, передаю в него эту основную ссылку, поток делает GET запрос на сайт, вытаскивает от туда ссылки их может быть сколько угодно, но не больше 10 (имеется ввиду в каждом из 4 потоков), с каждой такой ссылкой создается еще один поток, в него передается эта ссылка, от туда я парсю цифры, мне их нужно сложить со всеми остальными этими 10 потоками (ну или меньше) и потом эти цифры нужно вывести в нужный listview. Надеюсь понятно объяснил задачу.
nibufep вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Дождаться завершения работы процедуры Shouldercannon Общие вопросы Delphi 3 13.11.2013 14:09
Дождаться завершения работы командной строки ivt22 Общие вопросы Delphi 21 01.11.2013 11:59
Дождаться завершения другой программы в консоле delphi SawaMEN Общие вопросы Delphi 4 09.09.2013 14:26
Как дождаться завершения запущенного приложения DennerV Win Api 5 13.08.2010 13:48
Как дождаться завершения процедуры? Hintman Win Api 6 14.10.2009 14:46