![]() |
Модераторы: korob2001, ginnie |
![]() ![]() ![]() |
|
infodime |
|
|||
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 30.9.2006 Репутация: нет Всего: нет |
Помогите плз реализовать такое многопоточное приложение под линуксом:
Нужно фетчить и обрабатывать много разных страниц с помощью LWP во много потоков, и чтобы все работало максимально быстро. Я думаю сделать с помощью форков. С LWP проблем нет, но не пойму, как отследить чтобы было запущено одновременно например 100 детей и не больше? Пока приходит мысль только смотреть, скажем, раз в 5 секунд таблицу процессов, сколько запущено форков. Но это ведь будет тормозить? Да и не красиво как-то. Или может лучше будет реализовать это с помощью threads? В поиске не нашел ![]() Спасибо. |
|||
|
||||
Usya |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 154 Регистрация: 7.6.2005 Репутация: нет Всего: нет |
А тебе админ разрешит запускать сто процессов одновременно?
Если да, то можно поступить следующим образом: 1) Каждый потомок будет создавать временный файл с каким-либо именем (главное, чтобы не было повторений) и удалять после своей работы, а родитель каждые пять секунд (можно реализовать используя, например, sleep(5)) отслеживать сколько файлов существует и если не хватает, то создавать новых потомков. 2) У родителя создать массив с номерами соответствующих процессов. Обход процессов по аналогии каждые 5 секунд. Единственное, могут быть некоторые накладки - потомка уже нет, а процесс с соответствующим номером существует в связи с запуском другой проги.
На счет этого тоже не мешало бы уточнить - есть ли такая возможность на серваке? --------------------
Я не волшебник, я только учусь... |
|||
|
||||
Nab |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
На CPAN в каталоге с LWP лежит вот такой модуль
ParallelUserAgent Он именнно для этого по идее предназначен, учитывая что у меня задача похожая, то не хочу изобретать велосипед. Подозреваю эти вопросы не у нас первых возникли, и есть готовые решения... Посему на днях буду ковырять этот и другие Spiders, есть еще разные на CPAN... -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
JUmPER |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 196 Регистрация: 22.8.2006 Репутация: нет Всего: 3 |
а вот если ParallelUserAgent не понравится, то можно же просто потоки юзать...
вместо процессов -- это 1 экономичнее 2 удобнее 3 и админы орать не будут --------------------
Существует 10 типов людей: те, которые понимают двоичную систему, и те, которые ее не понимаютСуществует 10 типов людей: те, кто понимают троичную систему, те, кто ее не понимают и те, кто путает ее с двоичной |
|||
|
||||
Ezh |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 11.9.2006 Репутация: нет Всего: нет |
тема старая - юзай POE и будет тебе счастье (POE::Wheel::Run), а с потоками связываться не советую, очень там еще много "сюрпризов", особенно под большой нагрузкой
|
|||
|
||||
Buhalich |
|
|||
Новичок Профиль Группа: Участник Сообщений: 28 Регистрация: 14.9.2006 Репутация: нет Всего: нет |
||||
|
||||
alexu_id |
|
|||
Новичок Профиль Группа: Участник Сообщений: 15 Регистрация: 5.10.2006 Репутация: нет Всего: нет |
согласен с Ezh, поскольку сам только что занимался этой самой многопоточностью. на практике через POE http://poe.perl.org работает быстрее и нагрузка на сервер меньше. Правда не могу понять как это происходит
![]() как альтернативный вариант POE: для форков можно создать глобальный hash который содержит потомков и в цикле отслеживать его размер, а контролировать умирающих потомков в hash через сигнал #! /usr/bin/perl use POSIX qw( :signal_h :errno_h :sys_wait_h ); use LWP::Simple; my $TIMEOUT = 300; # задержка my $MAX_THREADS = 100; # максимальное количество потоков my %CHILDPIDS = (); # потомки $SIG{ CHLD } = \&REAPER; # сигнал когда потомок кирдык my @urls= (); # список urls # основной цикл while( ) { for( my $t = 0; $t <= $#urls; $t ++ ) { my $url = $urls[$t]; if( my $pid = fork ) { $CHILDPIDS{ $pid } = $pid if( defined $pid ); } else { my $content = $content = get($url); # ну и тут то что надо дальше } while( $#{[ keys %CHILDPIDS ]} + 1 == $MAX_THREADS ){} } sleep( $TIMEOUT ); # задержка } exit(0); sub REAPER{ while( my $kid = waitpid( -1, WNOHANG ) ){ last if $kid == -1; if( WIFEXITED( $? ) ){ delete( $CHILDPIDS{ $kid } ); } } $SIG{ CHLD } = \&REAPER; } Это сообщение отредактировал(а) alexu_id - 12.10.2006, 07:54 |
|||
|
||||
infodime |
|
|||
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 30.9.2006 Репутация: нет Всего: нет |
alexu_id спасибо за пример, но че-то он не работает
Через какое-то время все форки отрабатывают, а новые перестают создаваться Вроде как отработанные не удаляются из хеша. |
|||
|
||||
Ezh |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 11.9.2006 Репутация: нет Всего: нет |
POE прост и отлажен
Он стар как ... мамонта, там уже ошибок-то, наверное, не осталось Кусок из моего кода
Лимит по форкам это keys(%{$heap->{task}})<2 Если что не понятно, то советую юзать perl -d и $DB::single = 1 - это все лучше меня объяснит ![]() |
|||
|
||||
infodime |
|
|||
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 30.9.2006 Репутация: нет Всего: нет |
Ezh, спасибо большое! Разобрался с POE - все заработало как надо, очень удобная вещь
![]() Есть несколько непонятых моментов, проясните плз ![]() Мне нужно сделать так: стартуется первая функция, в ней делается выборка из базы, скажем на 2000 урлов. По аналогии с твоим кодом, пусть эта функция называется transformerLoop1 Из нее вызывается другая функция, transformerLoop2, в которой обрабатывается в многопоточном режиме (форками, с помощью POE::Wheel::Run) каждый урл из этого массива, делается shift из массива, и когда в нем остается 0 элементов, вызывается опять transformerLoop1 где делается выборка на следующие 2000 урлов Вопрос: как правильно организовать обмен переменными? Чтобы из массива, который был создан в функции transformerLoop1 правильно удалялись элементы (shift) всеми форками, которые порождаются функцией transformerLoop2? Я сделал с помощью $heap, но правильно ли это? И второй вопрос. Если выборку делать из mysql в функции transformerLoop1 с помощью обычного DBI то он на второй выборке отваливается с фразой Mysql server has gone away, хотя дисконнект я не вызывал. Покопавшись в гугле, сделал с помощью EasyDBI и SimpleDBI А как правильней? ![]() Спасибо |
|||
|
||||
Ezh |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 11.9.2006 Репутация: нет Всего: нет |
У тебя что-то с архитектурой... В твоем варианте я вряд ли что то посоветую
Я бы сделал так: есть два набора форкающихся объектов 1 набор - запрос 2000 урл из базы и заливка результатов в пул 2 набор - обработка уже запрошенных урл в пуле синхронизация работы наборов объектов и хранение пула все с помощью основного процесса то есть набор 1 обращается к родителю и набор 2 обращается к родителю, но напрямую никогда 1 и 2 не взаимодействуют ЗЫ IMHO есть heap объекта и есть heap родителя - не стоит их мешать ЗЗЫ 1ый набор ждет пустого пула, если пул родителя пуст, то заливает туда очередную порцию данных по факту IMHO должно получиться то, что ты хочешь DBI не совсем fork safe ![]() Добавлено @ 12:32 естественно 1ый набор будет состоять только из 1ого процесса ![]() |
|||
|
||||
infodime |
|
|||
Новичок Профиль Группа: Участник Сообщений: 4 Регистрация: 30.9.2006 Репутация: нет Всего: нет |
Ezh, спасибо, сделал, как ты посоветовал - все ок
![]() Возникла другая проблема, не связанная с этим На одном компе почему-то остаются зомби. Т.е. процесс, который тянет и парсит урлы родился, отработал, умер, а зомби остался. Через какое-то время таблица процессов переполняется и демон умирает. Это все происходит на FedoraCore последней, Xeon 1гб памяти Что интересно, на другом компе зомби не создаются.. там - gentoo и athlon xp 1gb памяти. Не знаешь, в какую сторону копать? И вообще, как отлавливать, почему эти зомби появляются? И второй вопрос: Ставлю максимальное число детей в 150, смотрю таблицу процессов - число все время колеблется в пределах 60-110. Память при этом не вся расходуется А если плодить процессы, которые выполняют только sleep(60) - то создается ровно 150 процессов. Из-за чего не досоздаются процессы? |
|||
|
||||
Ezh |
|
|||
Новичок Профиль Группа: Участник Сообщений: 21 Регистрация: 11.9.2006 Репутация: нет Всего: нет |
вообще зомби это процесс, который помер, но не похоронен
![]() Ниже кусок из changes POE, проверь версию на FC, если старая - проапгрейдь до 0.38 sig() reference count rolled back. sig_child() to wait on a particular PID (no more checking every SIGCHLD's PID for validity). Plus it holds a reference count. And it cancels itself once the interesting PID has been delivered. Maybe some other stuff, but those are the big ones. No other changes are planned before 0.38, but some minor patches might sneak in. Expect it on CPAN early this week. Кроме того, можешь в код родителя вставить принудительную чистку в цикле - пока есть живые мертвецы ($pid>-1) - хоронить и пускать ее перед каждым вызовом нового процесса (конечно это не особо красиво) Что-то типа
По второму вопросу, не уверен, но сам с таким тоже встречался. Мои размышления, могу быть не прав. Т.к. проца у тебя только 2ва а потоков много больше, то при росте количества потоков время User CPU стремится к нулю, а время System CPU к бесконечности, т.к. любой форк это тоже ресурсоемкая операция, так что если ты сделаешь максимум 10 процессов, то у тебя будет 9 работать, сделаешь 10^6 процессов и у тебя все ресурсы уйдут на форки. Именно поетому при компиляции рекомендуют пускать N+1 процессов, где N количество CPU. IMHO ты смело можешь понизить кол-во потоков до 100 и производительность парсинга либо останется та же, либо увеличится, но пренебрежительно мало. |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Perl" | |
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Perl: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |