Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Threads + nested child processes = блокировка? 
:(
    Опции темы
_hunter
  Дата 3.6.2011, 11:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



Добрый день,

 Помогите побороть проблему: есть скрипт, последовательно вызывающий другой скрипт (с параметрами). На уровне:
Код

foreach $tree (@treeListIn)
{
    my ($statusOut, @lines) = call_cmd_ex($_);
    if ($statusOut)
    {
        die "Error\n";
    }
}

Я эту "штуку" решил сделать многопоточной:
Код

foreach $tree (@treeListIn)
{
    while (threads->list(threads::running) > 0) {
        log_msg("Waiting for worker\n");
        sleep(5);
    }
 
    threads->create(sub {
            my ($statusOut, @lines) = call_cmd_ex(@_);
            return ($statusOut);
        }, $_);
}

И вот тут начинается самое интересное: на первой же итерации второй скрипт успешно стартует, успешно запускает еще один процесс (и он успешно завершается), запускает следующий task и он (этот task) "подвисает": State: Wait:WrLpcReply.
"Main thread" в это время крутится в while (threads->list(threads::running) > 0).

 Подскажите из-за чего такое может происходить (и что с этим делать).
( Windows XP, CLI, Perl 5.8.8)

 С уважением...


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
afiskon
Дата 3.6.2011, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 31.3.2011
Где: Россия, Москва

Репутация: нет
Всего: 4



Вы что-то не так делаете, потоки по-другому используются (см пункт 10). Еще у вас может быть дэдлок.
PM MAIL WWW   Вверх
_hunter
Дата 3.6.2011, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



В смысле "по-другому"?

В "беспоточном" варианте локов нету, откуда бы им взяться в однопоточном?.. + Как-то это проверить можно?


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
EcSYZ
Дата 3.6.2011, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 79
Регистрация: 21.6.2007

Репутация: 1
Всего: 1



Как уже заметил выше afiskon, это пример довольно странного использования потоков.
Если уж надо сделать это многопоточным, то цикл надо засовывать внуть самого потока, а массив @treeListIn рассшаривать.
А в конце просто отловить все потоки.
PM MAIL WWW   Вверх
_hunter
Дата 3.6.2011, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



Что тут странного? -- Я хочу запустить столько потоков, сколько у меня "тасков".
Если foreach $tree (@treeListIn) я засуну в поток -- у меня будет "двух-поточное" исполнение: main и worker.
Или я упустил что-то?


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
afiskon
Дата 3.6.2011, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 31.3.2011
Где: Россия, Москва

Репутация: нет
Всего: 4



Ну я вот лично не понимаю, что это делает:
Код

    while (threads->list(threads::running) > 0) {
        log_msg("Waiting for worker\n");
        sleep(5);
    }

Может, просветите?
PM MAIL WWW   Вверх
DurRandir
Дата 3.6.2011, 14:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



1) А что внутри call_cmd_ex?
2) А какой смысл запускать ровно 1 поток, и ждать его завершения? 
3) Вы не вызываете для потока ни detach, ни join
4) Стоит посмотреть на готовые модули, реализающие пул потоков (к примеру, Thread::Pool)
5) Почему пул? Потому что, если в @treeListIn достаточно элементов, то вы быстро вылетите с OOM.
PM   Вверх
_hunter
Дата 3.6.2011, 15:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



1) По-сути просто вызов $status = open(CMD, "$cmdIn 2>&1 |" ); с "обвязкой". Если нужно -- могу выложить.
2) Это для "отладки". Потом будет 10/20.
3) Это  я планирую делать за foreach'ем
4) 5) если память -- единственная проблема -- смысл заморачиваться?..


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
EcSYZ
Дата 3.6.2011, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 79
Регистрация: 21.6.2007

Репутация: 1
Всего: 1



Код

#!/usr/bin/perl
$|=1;
use common::sense;
use threads;
use threads::shared;

my @treeListIn;
share(@treeListIn);

#...

for(1 .. scalar @treeListIn){
    threads->create(\&run,$_);
}
foreach(threads->list) { $_->join; }

sub run
{
   while(scalar @treeListIn != 0)
   {
      pop @treeListIn;
      my ($statusOut, @lines) = call_cmd_ex($_);
      if ($statusOut) {
       die "Error\n";
      }
   }
}

А вот примерно такой вариант не катит ?

Это сообщение отредактировал(а) EcSYZ - 3.6.2011, 15:33
PM MAIL WWW   Вверх
_hunter
Дата 3.6.2011, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



Не совсем то, что нужно: если я правильно понял логику (конструкцию "for(1 ..  " я увидел впервые) этот пример не гарантирует что будет запущенно "не больше N" потоков. + Мне "ближе" логика "один поток выполнил одну cmd и умер". Может в Perl'е оно и по-другому принято...


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
DurRandir
Дата 3.6.2011, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



Код

use threads;

push @threads, threads->create(sub {
  my ($statusOut) = call_cmd_ex($_);
  print "Error processing $_\n" if $statusOut;
}) foreach @treeListIn;
$_->join() foreach @threads;


Тупо запустить в параллель всё из @treeListIn. Если надо - дописать сборку обратно @lines (по приведённому фрагменту они просто отбрасываются).

Это сообщение отредактировал(а) DurRandir - 3.6.2011, 16:32
PM   Вверх
EcSYZ
Дата 3.6.2011, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 79
Регистрация: 21.6.2007

Репутация: 1
Всего: 1



ну вот пару минут на переделку, и этот код запускает по $threads_max потоков и ждёт их завершения, после чего запускает следующую пачку.
Код

#!/usr/bin/perl
$|=1;
use common::sense;
use threads;
use threads::shared;

my $threads_max=20;
my @treeListIn;
share(@treeListIn);

#...

while(scalar @treeListIn != 0){
   for( 1 .. $threads_max ){
      threads->create(\&run,$_);
   }
   foreach(threads->list) { $_->join; }
}

sub run
{
      pop @treeListIn;
      my ($statusOut, @lines) = call_cmd_ex($_);
      if ($statusOut) {
       die "Error\n";
      }
}

PM MAIL WWW   Вверх
Pfailed
Дата 3.6.2011, 17:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Потоки здесь не нужны. open + select достаточно


--------------------
PM MAIL   Вверх
_hunter
Дата 3.6.2011, 20:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



DurRandir, EcSYZ, теперь немного нескромный вопрос: в чем принципиальная разница с моим "кодом"? -- join() -- как я уже говорил: он будет за циклом. И проблема, в общем-то, не в обработке результатов потока, а в том, что поток (первый же) "недорабатывает".

Pfailed, в смысле не нужны? -- Мне за максимально короткое время нужно выполнить пачку слабо зависящих друг-от-друга задач. Это, вроде-как, потоки "по книжке"...


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
EcSYZ
Дата 3.6.2011, 20:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 79
Регистрация: 21.6.2007

Репутация: 1
Всего: 1



Думаю что проблема в том, что у большинства вызывает вопросы вот эта конструкция:
Код

    while (threads->list(threads::running) > 0) {
        log_msg("Waiting for worker\n");
        sleep(5);
    }


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

Цитата

_hunter
...
в чем принципиальная разница с моим "кодом"?
...

а мне вот не понятно, в чём их принципиальное сходство, если исключить что и там и тут юзаются потоки.

PM MAIL WWW   Вверх
Pfailed
Дата 3.6.2011, 20:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Цитата(_hunter @  3.6.2011,  20:02 Найти цитируемый пост)
Мне за максимально короткое время нужно выполнить пачку слабо зависящих друг-от-друга задач. Это, вроде-как, потоки "по книжке"

Судя по описанному вам нужно запустить внешние программы. Если дело происходит не в windows, то open с пайпом создает fork. Особого смысла выводить создание потомков в отдельные потоки не вижу. Если нужно получить вывод от запущенных программ используется select.


--------------------
PM MAIL   Вверх
EcSYZ
Дата 3.6.2011, 20:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 79
Регистрация: 21.6.2007

Репутация: 1
Всего: 1



Цитата(_hunter @ 3.6.2011,  11:24)
...
( Windows XP, CLI, Perl 5.8.8)
...

внезапно ...
PM MAIL WWW   Вверх
Pfailed
Дата 3.6.2011, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



windows, как известно, sux


--------------------
PM MAIL   Вверх
afiskon
Дата 4.6.2011, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 31.3.2011
Где: Россия, Москва

Репутация: нет
Всего: 4



ТС, прочитайте внимательно perldoc, выясните разницу мужде джойнабл и детачед нитями и как ими пользоваться в Perl. 
PM MAIL WWW   Вверх
_hunter
Дата 6.6.2011, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

Репутация: нет
Всего: 98



ОК, похоже мой "простой" пример увел нас не в ту сторону...
Попробуем с другим примером:
Код

log_msg("\t\t\tStarting thread\n");
threads->create(sub {
        my ($statusOut, @lines) = do_cmd(@_);
        return ($statusOut);
    }, $cmd)->join();
log_msg("\t\t\tThread finished\n");

где
Код

sub do_cmd
{
    my( $cmdIn )                   = shift;

    my( @linesOut )                = ();
    my( $statusOut )               = 0;

    my( $rval )                    = 0;
    my( $status )                  = 0;
    my( $cmd_name )                = '';
    my( $line )                    = '';

    #***************************************************************************
    #
    #  Issue the command
    #
    #***************************************************************************

    $status = open(CMD, "$cmdIn 2>&1 |" );

    if ( $status )
    {
        @linesOut = <CMD>;

        close(CMD);

        #***************************************************************************
        #
        #  Get return value of shell command.
        #
        #***************************************************************************

        $rval      = $?;
        $statusOut = $rval / 256;

        if ($statusOut)
        {
            log_msg( "$0: do_cmd: ERROR: The command failed: Return Value = $rval, Return Code = $statusOut\n" );

        }
    }

    #***************************************************************************
    #
    #  The open failed
    #
    #***************************************************************************

    else
    {
        log_msg( "$0: do_cmd: ERROR: The command could not be executed.\n" );

        $statusOut = 1;
    }

    return( $statusOut, @linesOut );

}   ## end -- do_cmd()



--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0603 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.