Perl несколько задач - PullRequest
4 голосов
/ 18 июня 2010

Я закончил свою предыдущую многопоточную программу, которая использует потоки Perl, и она работает в моей системе.Проблема в том, что на некоторых системах, на которых он должен работать, поддержка потоков не компилируется в perl, и я не могу установить дополнительные пакеты.Поэтому мне нужно использовать что-то другое, чем потоки, и я перевожу свой код на использование fork ().Это работает в моей системе Windows при запуске подзадач.

Несколько проблем:

  1. Как определить, когда завершается дочерний процесс?Я создал новые потоки, когда число потоков было ниже определенного значения, мне нужно отслеживать, сколько потоков запущено.Что касается процессов, как я узнаю, когда кто-то выходит, чтобы я мог отслеживать, сколько существует в данный момент, увеличивая счетчик при его создании и уменьшая при выходе один?

  2. Является ли файлВвод / вывод с использованием дескрипторов, полученных с помощью OPEN, при открытии родительским процессом безопасно в дочернем процессе?Мне нужно добавить в файл для каждого из дочерних процессов, безопасно ли это и в Unix.

  3. Есть ли альтернатива форку и потокам?Я попытался использовать Parallel :: ForkManager, но он не установлен в моей системе (используйте Parallel :: ForkManager; выдал ошибку), и мне абсолютно необходимо, чтобы мой скрипт perl работал на всех системах unix / windows без установки каких-либо дополнительных модулей.

Ответы [ 2 ]

6 голосов
/ 18 июня 2010

Типичное использование:

use POSIX ':sys_wait_h';    # for &WNOHANG

# how to create a new background process
$pid = fork();
if (!defined $pid) { die "fork() failed!" }
if ($pid == 0) { # child
    # ... do stuff in background ...
    exit 0;      # don't forget to exit or die from the child process
} 
# else this is the parent, $pid contains process id of child process
# ... do stuff in foreground ...

# how to tell if a process is finished
# also see  perldoc perlipc
$pid = waitpid -1, 0;           # blocking wait for any process
$pid = wait;                    # blocking wait for any process
$pid = waitpid $mypid, 0;       # blocking wait for process $mypid
# after blocking wait/waitpid
if ($pid == -1) {
    print "All child processes are finished.\n";
} else {
    print "Process $pid is finished.\n";
    print "The exit status of process $pid was $?\n";
}

$pid = waitpid -1, &WNOHANG;    # non-blocking wait for any process
$pid = waitpid $mypid, 0;       # blocking wait for process $mypid
if ($pid == -1) {
    print "No child processes have finished since last wait/waitpid call.\n";
} else {
    print "Process $pid is finished.\n";
    print "The exit status of process $pid was $?\n";
}

# terminating a process - see  perldoc -f kill  or  perldoc perlipc
# this can be flaky on Windows
kill 'INT', $pid;               # send SIGINT to process $pid

Детали Гори в perldoc -f fork, waitpid, wait, kill и perlipc.Сведения из perlipc о настройке обработчика для событий SIGCHLD должны быть особенно полезны, хотя это не поддерживается в Windows.

Ввод / вывод между разветвленными процессами в целом безопасен в Unix и Windows.Файловые дескрипторы являются общими, поэтому для чего-то подобного

open X, ">", $file;
if (fork() == 0) {  # in child
    print X "Child\n"; 
    close X;
    exit 0;
}
# in parent
sleep 1;
print X "Parent\n";
close X;

и дочерний, и родительский процессы будут успешно записывать в один и тот же файл (однако следует помнить о буферизации вывода).

3 голосов
/ 18 июня 2010

Взгляните на waitpid.Вот некоторый код, который имеет девять задач, которые необходимо выполнить (с 1 по 9).Для выполнения этих задач потребуется до трех рабочих.

#!/usr/bin/perl

use strict;
use warnings;
use POSIX ":sys_wait_h";

my $max_children = 3;
my %work = map { $_ => 1 } 1 .. 9;
my @work = keys %work;

my %pids;
while (%work) {
    #while there are still empty slots
    while (@work and keys %pids < $max_children) {
        #get some work for the child to do
        my $work = shift @work;

        die "could not fork" unless defined(my $pid = fork);

        #parent
        if ($pid) {
            $pids{$pid} = 1;
            next;
        }

        #child
        print "$$ doing work $work\n";
        sleep 1;
        print "$$ done doing work $work";
        exit $work;
    }

    my $pid = waitpid -1, WNOHANG;

    if ($pid > 0) {
        delete $pids{$pid};
        my $rc = $? >> 8; #get the exit status
        print "saw $pid was done with $rc\n";
        delete $work{$rc};
        print "work left: ", join(", ", sort keys %work), "\n";
    }

    select undef, undef, undef, .25;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...