【问题标题】:Can I reuse joined threads in perl?我可以在 perl 中重用加入的线程吗?
【发布时间】:2014-11-14 06:12:56
【问题描述】:

我有一个模块正在运行多个线程并将它们推送到线程列表中。

例如:

#!/usr/bin/perl

#test_module.pm

package test_module;

use strict;
use warnings;
use threads;

sub main {

    my $max_threads = 10;
    my @threads     = ();

    # create threads
    while (scalar @threads < $max_threads) {
        my $thread = threads->new(\&thread_sub);
        push @threads, $thread;
    }

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

sub thread_sub {
    my $id = threads->tid();
    print "I am in thread $id\n";
}

1;

问题是我从一个 Perl 脚本多次调用这个模块,而不是消除旧线程并创建新线程,线程 ID 只是不断增加。我听说如果你没有正确地摆脱 Perl 中的旧线程,这会导致内存泄漏并减慢你的程序,这是真的吗?我的旧线程中的数据是否只是在内存中占用空间?

如果是这样,这可能会成为一个大问题,因为我的脚本将成为一个更大的程序的一部分,该程序可能会生成数百或数千个线程,所有这些线程即使在使用完之后也会占用内存。我怎样才能阻止这种情况发生?我的线程可以重复使用吗?

这是一个示例脚本,它将调用模块并显示线程将如何继续增加,即使我加入了旧线程(我认为“加入”是你在它们之后清理的方式,我做错了什么吗? ) 这个脚本的使用方式我无法承受旧线程的内存占用空间。

例如:

#!/usr/bin/perl

#testing.pl

use strict;
use warnings;
use test_module;

test_module::main();
test_module::main();
test_module::main();

system 'pause';

谢谢!

【问题讨论】:

  • 为什么要重用线程ID?
  • 我想我真正想知道的是所有线程内存是否真的在“加入”时释放。 id 不断增加的事实使得旧线程似乎仍然存在于内存中,即使它们已经“加入”了。
  • 线程 id 递增与进程 id 递增一样是一个红鲱鱼。两者都不意味着正在发生耗尽。

标签: multithreading perl thread-safety threadpool


【解决方案1】:

不要担心线程 ID 会增加 - 这并不意味着正在运行的线程数会增加。一旦一个线程被joined 它已经完成执行并被终止。

但是,连续重生线程也不理想——在 perl 中创建线程并不是一个特别轻量级的操作。因此,如果您必须做类似的事情,并且特别关注效率,请转而查看 fork()。

我发现我倾向于使用“工作线程”模型,使用Thread::Queue:

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

sub worker_thread {
    while ( my $item = $processing_q -> dequeue() ) {
       # do stuff to $item
    }
}

for ( 1 .. $num_threads ) {
    my $thr = threads -> create ( \&worker_thread );
}

$processing_q -> enqueue ( @generic_list_of_things ); 
$processing_q -> end;

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

这会将一批项目送入队列,您的工作线程将一次处理一个 - 这意味着您可以运行一个合理的数字,而无需连续重生。

作为替代方案 - 看看 Parallel::ForkManager - fork 风格的并行处理最初可能看起来违反直觉,但 fork() 是 Unix 系统上的本机系统调用,因此它往往会得到更好的优化。

【讨论】:

  • 我基本上创建了自己的队列,但我会研究那个模块,因为它可能会简化事情。
  • 它内置了锁定语义,使其更整洁。不一定更有效率的头脑,但清晰的代码有它自己的优点。我特别喜欢 end() 选项 - 因为这样子内的 while 循环将返回 undef 并退出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多