巧妙地在Perl中跨线程共享文件数据的方法

时间:2011-10-27 15:30:49

标签: multithreading perl

我正在寻找一种可靠(并且可能很聪明)的方式来在Perl中的可变数量的线程之间共享文件数据。我希望有一个设置,主线程从文件读取行,而其他工作线程处理单个条目。

到目前为止,我已经尝试过使用Thread :: Queue并且没有太多好运。当我到达文件末尾时,一旦主线程完成读取,大多数线程都处于阻塞状态,等待从中读取数据。因此,线程有些陷入困境,而join()无法将它们卷回来。

当对队列使用非阻塞访问时,线程容易陷入“试图获取数据,未定义,尝试获取数据......”的紧密循环中,这最终会破坏CPU和没有工作。即使只有一个工作线程,每个线程通常至少会获得该紧密循环的几次迭代。投入睡眠()并没有太大帮助,因为它只需要整数值(睡眠(0)无效,睡眠(1)太慢)。

最理想的是,我希望可以共享输入文件的流并让每个线程锁定它,从中读取一行,然后解锁它,但禁止/不支持共享globs。我会先将整个文件加载到内存中,但看到它有4000万个条目(作为低端估计),它并不是非常可行。

所以这就是你们都进来的地方。我需要一种方便的方法来在主线程和工作线程之间实现读取器/处理器设置,这不会浪费过多的CPU等待数据并将线程留在连接中(一旦读者到达文件末尾,就会出现状态。

非常感谢任何帮助或想法!

2 个答案:

答案 0 :(得分:4)

这个小测试对我有用。 (我之前从未使用过螺纹,但过去使用过叉子和管道做过同样的事情)。所以基本上需要告诉你的线程在要求他们加入之前完成,为此我在队列中粘贴了一个undef。

#!/usr/bin/env perl

use strict;
use warnings;

use threads;
use Thread::Queue;

use constant MAX_THREADS => 5;

sub process_data
{
    my( $q ) = @_;
    while( defined( my $data = $q->dequeue() ) )
    {
        print "Thread[".threads->tid()."]: Processing data($data)\n";
    }

    print "Thread[".threads->tid()."]: Got end message\n";
} # END process_data

# Main program
{
    my @threads;
    my $q = Thread::Queue->new();
    foreach ( 1 .. MAX_THREAD )
    {
        push( @threads, async { process_data($q) } );
    }

    while( my $line = <STDIN> )
    {
        chop( $line );
        $q->enqueue( $line );
    }

    foreach my $thread ( @threads )
    {
        $q->enqueue( undef );
    }

    foreach my $thread ( @threads )
    {
        $thread->join();
    }
}

答案 1 :(得分:2)

使用主线程读取,然后使用coroutines处理行:

use strict;
use warnings;
use Coro;

my $sem = Coro::Semaphore->new(10); # maximum of ten semaphores
while my $line ( <$FILE> ) {
    $sem->down;
    async {
        dostuff($line);
        $sem->up;
    };
}