我正在寻找一种可靠(并且可能很聪明)的方式来在Perl中的可变数量的线程之间共享文件数据。我希望有一个设置,主线程从文件读取行,而其他工作线程处理单个条目。
到目前为止,我已经尝试过使用Thread :: Queue并且没有太多好运。当我到达文件末尾时,一旦主线程完成读取,大多数线程都处于阻塞状态,等待从中读取数据。因此,线程有些陷入困境,而join()无法将它们卷回来。
当对队列使用非阻塞访问时,线程容易陷入“试图获取数据,未定义,尝试获取数据......”的紧密循环中,这最终会破坏CPU和没有工作。即使只有一个工作线程,每个线程通常至少会获得该紧密循环的几次迭代。投入睡眠()并没有太大帮助,因为它只需要整数值(睡眠(0)无效,睡眠(1)太慢)。
最理想的是,我希望可以共享输入文件的流并让每个线程锁定它,从中读取一行,然后解锁它,但禁止/不支持共享globs。我会先将整个文件加载到内存中,但看到它有4000万个条目(作为低端估计),它并不是非常可行。
所以这就是你们都进来的地方。我需要一种方便的方法来在主线程和工作线程之间实现读取器/处理器设置,这不会浪费过多的CPU等待数据并将线程留在连接中(一旦读者到达文件末尾,就会出现状态。
非常感谢任何帮助或想法!
答案 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;
};
}