【问题标题】:Is there a multiprocessing module for Perl?Perl 有多处理模块吗?
【发布时间】:2011-12-17 09:40:28
【问题描述】:

Perl 有多处理模块吗?与 Python 的 multiprocessing module 提供的功能类似的东西。

我知道我可以使用 Perl 构建类似的功能,但我正在寻找已经实现的功能。

【问题讨论】:

  • 不要忘记 Perl 有开箱即用的 forkexec
  • 是的,我也将它添加到问题中。
  • @PlatinumAzure 棘手的部分是“多处理包同时提供本地和远程并发,”我不知道是否有针对 remote 的可移植抽象 部分。
  • 如果我需要远程并发,我会开始考虑类似 gearman 和 Gearman::XS 的东西。如果是本地的,则使用 fork/exec 或 Parallel::ForkManager 来管理进程。
  • 除了 fork() 之外还有线程(假设您的 Perl 已针对该支持进行了编译)。见“perlthrtut”DOC

标签: multithreading perl multiprocessing


【解决方案1】:

forks 提供与threads 相同的出色接口,但使用进程而不是线程。

use forks;  # Or: use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

my @workers;
for (1..NUM_WORKERS) {
   push @workers, async {
      while (defined(my $job = $q->dequeue())) {
         ...
      }
   };
}

$q->enqueue(...);

$q->enqueue(undef) for @workers;
$_->join for @workers;

将分叉与 Forks::Super 进行比较。

请记住,这些假设是 Forks::Super 擅长的情况!

use Forks::Super;
sub do_something { my @args = @_; ... }
$process = fork { sub => \&do_something, args => [@args] };
$process->wait;

可以写成

use forks;
sub do_something { my @args = @_; ... }
$process = async { do_something(@args) };
$process->join;

---

use Forks::Super;
my $x = 42;
my @y = ();
my %z = ();
sub do_something_else {
    $x = 19;
    @y = qw(foo bar);
    %z = (foo => 'bar');
}
$process = fork { sub => 'do_something_else', share => [\$x, \@y, \%z ] };
$process->wait;

可以写成

use forks;
use forks::shared;
my $x :shared = 42;
my @y :shared = ();
my %z :shared = ();
sub do_something_else {
    $x = 19;
    @y = qw(foo bar);
    %z = (foo => 'bar');
}
$process = async { do_something_else() };
$process->join;

---

use Forks::Super;
use IO::Handle;
pipe my $child_read, my $parent_write;
pipe my $parent_read, my $child_write;
$parent_write->autoflush(1);
$child_write->autoflush(1);
sub square {
    while (my $x = <$child_read>) {
        chomp($x);
        print {$child_write} $x ** 2, "\n";
    }
    close $child_write;
}
$process = fork { sub => 'square' };
print { $parent_write } "9\n";
chomp( my $result = <$parent_read> );  # 81
close $parent_write;
$process->wait;

可以写成

use forks;
use Threads::Queue;
my $req = Threads::Queue->new();
my $resp = Threads::Queue->new();
sub square { $_[0] ** 2 }
$process = async {
    while (defined(my $x = $req->dequeue())) {
        $resp->enqueue( square($x) );
    }
};
$req->enqueue(9);
my $result = $resp->dequeue();  # 81
$resp->enqueue(undef);
$process->join;

---

use Forks::Super;
sub square_root {
    sleep 1 && seek STDIN,0,1 while eof(STDIN); # ok, this is a workaround for an existing bug :-(
    while (my $x = <STDIN>) {
        chomp($x);
        print sqrt($x), "\n";
    }
}
$process = fork { sub => 'square_root', child_fh => 'in,out,block' };
$process->write_stdin("81\n");
chomp( $result = $process->read_stdout() );  # 9
$process->close_fh('stdin');
$process->wait;

可以写成

use forks;
use Threads::Queue;
my $req = Threads::Queue->new();
my $resp = Threads::Queue->new();
$process = async {
    while (defined(my $x = $req->dequeue())) {
        $resp->enqueue( sqrt($x) );
    }
};
$req->enqueue(81);
my $result = $resp->dequeue();  # 9
$resp->enqueue(undef);
$process->join;

【讨论】:

  • @jkysam,添加了 forks 和 Forks::Super 的比较。
【解决方案2】:

我认为Forks::Super 非常接近。它有一些功能可以在后台进程中运行任意子例程(或外部命令),监控后台进程并发出信号,并使进程间通信不那么痛苦。

use Forks::Super;

sub do_something { my @args = @_; ... }
$process = fork { sub => \&do_something, args => [@args] };
$process->wait;


my $x = 42;
my @y = ();
my %z = ();
sub do_something_else {
    $x = 19;
    @y = qw(foo bar);
    %z = (foo => 'bar');
}
$process = fork { sub => 'do_something_else', share => [\$x, \@y, \%z ] };
$process->wait;
# $x, @y, and %z are now updated with changes made in background process


# create your own pipes to use for IPC
use IO::Handle;
pipe my $child_read, my $parent_write;
pipe my $parent_read, my $child_write;
$parent_write->autoflush(1);
$child_write->autoflush(1);
sub square {
    while (my $x = <$child_read>) {
        print {$child_write} $x ** 2, "\n";
    }
    close $child_write;
}
$process = fork { sub => 'square' };
print {$parent_write} "9\n";
my $result = <$parent_read>;    # should be "81\n";
close $parent_write;

# or use the standard I/O handles for IPC
sub square_root {
    sleep 1 && seek STDIN,0,1 while eof(STDIN); # ok, this is a workaround for an existing bug :-(
    while (my $x = <STDIN>) {
        print sqrt($x), "\n";
    }
}
$process = fork { sub => 'square_root', child_fh => 'in,out,block' };
$process->write_stdin("81\n");
$result = $process->read_stdout(); #  =>  "9\n"

multiprocessing 模块和Forks::Super 都有很多功能。您对哪些特别感兴趣?

我是Forks::Super 的作者,我的目标是包含任何人们认为有用的并行处理功能,所以如果multiprocessing 中有您想要在 Perl 中使用的功能,请告诉我。

【讨论】:

  • 这正是我想要的。我得到了这个任务来增加并行性以改善我们拥有的一些 Perl 脚本的运行时间。我以前使用过 Python 的多处理,但在 Perl 中没有。当我开始转换脚本时,我会有更具体的问题。
  • 呃,我刚刚检查了这个模块是否安装在我的 Perl 中,显然不是。我希望像这样的基本东西是标准 Perl 包的一部分。 :(
  • 我在 Windows 10 上使用 Forks::Super 和 Strawberry Perl 5.30,当我使用 Forks::Super::fork( 'sub' => \&myFunc ... );它实际上并没有启动子进程。在 Windows 上,Forks::Super 是否有可能只是通过线程模拟正常的 Unix 分叉行为? :-\
  • 是的,要在 Windows 的后台运行 Perl 子例程,Forks::Super 将使用内置的 fork 调用,它会为子代码生成一个 pseudo-process跑进去。
  • @antred Perl“基于解释器的线程”(use threads)有这个问题。但它们是不同的,我相信所有这样的 Perl 线程都在单个 Windows 线程中运行。使用 fork() 仿真时,您会获得多个不同的 Windows 线程(而不是您在 POSIX 系统上获得的进程),这通常足够好。
【解决方案3】:

POE: Perl Object Environment 呢?它支持异步子进程。

【讨论】:

    【解决方案4】:

    您可以使用https://github.com/marioroy/mce-perl 类似于python多进程模块

    【讨论】:

    猜你喜欢
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 2017-12-11
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多