Модераторы: 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   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


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

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


 




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


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

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