0

我的 perl 脚本的一部分有问题,困扰了我好几天。总结一下,目的是分块读取一个大文件并对输入流进行一些操作(与我的问题无关)。当我第一次实现它时,我只是遍历了文件,然后在上面做了一些事情,就像这样:

while (read FILE, $buffer, $chunksize){ 
  callSomeOperation($buffer);
  # Do some other stuff
}

不幸的是,该文件非常大,并且操作在某种程度上很复杂,有许多函数调用,因此这导致内存稳步增加 perl 无法再分配内存并且脚本失败了。所以我做了一些调查并尝试了一些方法来最小化内存开销(在循环外定义变量,设置为 undef 等等),这导致分配的内存大小增加得更慢,但最后仍然失败。(如果我想得对,perl 将内存还给操作系统是……这在实践中不会发生。)

所以我决定将函数调用及其所有定义嵌套在一个子线程中,等待它的完成,加入,然后用下一个块再次调用线程:

while (read FILE, $buffer, $chunksize){
my $thr = threads->create(\&thrWorker,$buffer);
$thr->join();
}

sub thrWorker{
# Do the stuff here!
}  

如果线程加入,这可能是一个解决方案!但实际上并没有。如果我用 $thr->detach(); 运行它 一切正常,除了我同时得到数百个线程,这不是一个好主意,在这种情况下,我需要连续运行它们。

所以我对这个加入问题进行了一些调查,并得到一些声音说 perl 5.16.1 可能存在问题,所以我更新到 5.16.2 但它仍然没有加入。在邮件列表中的任何地方,我不记得我读过有人设法让线程加入 CPAN 模块 Thread::Queue 但这对我也不起作用。

所以我放弃了线程并试图分叉这个东西。但是对于叉子,“叉子”的总数似乎是有限的?无论如何,直到第 13 次到第 20 次迭代都很好,然后放弃了它不能再分叉的消息。

my $pid = fork();
if( $pid == 0 ){
       thrWorker($buffer);
    exit 0;
}

我还尝试使用 CPAN 模块 Parallel::ForkManager 和 Proc::Fork 但这没有帮助。

所以现在我不知何故被卡住了,无法自拔。也许别人可以!任何建议都非常感谢!

  1. 我怎样才能让这个东西与线程或子进程一起工作?
  2. 或者至少我怎样才能强制 perl 释放内存,以便我可以在同一个过程中做到这一点?

关于我的系统的一些附加信息:操作系统:Windows 7 64bit / Ubuntu Server 12.10 Perl on Windows:Strawberry Perl 5.16.2 64bit

我在 Stackoverflow 上的第一篇文章。希望我做对了:-)

4

2 回答 2

1

我推荐阅读:这个

我通常使用 Thread::Queue 来管理线程的输入。示例代码:

my @threads = {};
my $Q = new Thread::Queue;

# Start the threads
for (my $i=0; $i<NUM_THREADS; $i++) {
    $threads[$i] = 
        threads->new(\&insert_1_thread, $Q);
}

# Get the list of sites and put in the work queue
foreach $row ( @{$ref} ) {
    $Q->enqueue( $row->[0] );
    #sleep 1 while $Q->pending > 100;
} # foreach $row

# Signal we are done
for (my $i=0; $i<NUM_THREADS; $i++) {
    $Q->enqueue( undef ); }

$count = 0;
# Now wait for the threads to complete before going on to the next step
for (my $i=0; $i<NUM_THREADS; $i++) {
    $count += $threads[$i]->join(); }

对于工作线程:

sub insert_1_thread {
my ( $Q ) = @_;
my $tid = threads->tid;
my $count = 0;
Log("Started thread #$tid");

while( my $row = $Q->dequeue ) {
    PROCESS ME...
    $count++;
} # while

Log("Thread#$tid, done");
return $count;

} # sub insert_1_thread
于 2012-11-19T14:55:41.853 回答
0

我不知道它是否适合您,但是您可以创建一个块对象数组并像这样并行处理它们:

#!/usr/bin/perl

package Object; {
    use threads;
    use threads::shared;        

    sub new(){
        my $class=shift;
        share(my %this);
        return(bless(\%this,$class));
    }

    sub set {
       my ($this,$value)=@_;    
        lock($this);
#       $this->{"data"}=shared_clone($value);
        $this->{"data"}=$value;
    }

    sub get {
        my $this=shift; 
        return $this->{"data"};
    }
}


package main; {

use strict;
use warnings;

use threads;
use threads::shared;

    my @objs;
    foreach (0..2){
        my $o = Object->new();
        $o->set($_);
        push @objs, $o; 
    }

    threads->create(\&run,(\@objs))->join();

    sub run {
        my ($obj) = @_;     
        $$obj[$_]->get() foreach(0..2);        
    }
}
于 2012-11-19T15:32:43.487 回答