【问题标题】:How to use threads to replace looping a subroutine in perl/pdl如何使用线程来替换 perl/pdl 中的循环子例程
【发布时间】:2010-09-07 23:18:56
【问题描述】:

我有一个非常好的 perl 子例程,它是作为 perl 模块的一部分编写的。在不涉及太多细节的情况下,它将一个字符串和一个简短列表作为参数(通常取自终端)并输出一个值(现在,总是一个浮点数,但可能并非总是如此。)

现在,我的参数的列表部分有两个值,比如 (val1,val2)。我使用 for 循环将子例程的输出保存为 val1 和 val2 的数百个不同值。每次迭代几乎需要一秒钟才能完成 - 因此完成整个过程需要数小时。

我最近读到了一个神秘的(对我而言)名为“线程”的计算工具,它显然可以用极快的执行时间代替 for 循环。我一直无法理解这些是什么以及做什么,但我想它们与并行计算有关(我希望我的模块尽可能针对并行处理器进行优化。)

如果我将所有想要传递给 val1 的值保存为一个列表,比如 @val1 和 val2 相同,我如何使用这些“线程”为 val1 和val2? 此外,了解如何将此过程推广到也采用 val3、val4 等的子例程会很有帮助。

【问题讨论】:

  • 是的,我看过这个,但恐怕我还是一头雾水。我的 $thr = threads->create(sub { ... }, ...);似乎是我正在寻找的,但我不明白如何使用它。我已经看过教程等等,但我仍然对如何实现线程感到困惑。例如:我的 $thr = threads->create(sub { ... }, ...);制作一个与普通子程序完全相同但并行执行的子程序?这是我的假设,但我没有太多事情要做。
  • 不,它启动一个运行该子程序的线程,并返回一个线程对象,就像 perldoc 所说的那样。

标签: multithreading perl loops subroutine pdl


【解决方案1】:

更新:

我不使用 PDL,所以我不知道 PDL 中的线程与我一直在谈论的线程概念不完全对应。见PDL threading and signatures

首先,我们必须解释一下在 PDL 上下文中线程是什么意思,特别是因为线程这个术语在计算机科学中已经具有独特的含义,它在 PDL 中的用法只有部分一致。

但是,我认为下面的解释对您仍然有用,因为您需要知道常规意义上的线程是什么才能理解 PDL 线程的不同之处。

这里是背景的Threads entry on Wikipedia

使用线程不能神奇地让你的程序更快。 如果您有多个 CPU/内核,并且如果您正在执行的计算可以分成独立的块,使用线程可以让您的程序在同一时间执行多个计算时间并减少总执行时间。

最简单的情况是子任务是embarrassingly parallel,不需要线程之间的通信/协调。

关于可能的性能提升,请考虑以下程序:

#!/usr/bin/perl

use strict; use warnings;
use threads;

my ($n) = @ARGV;

my @threads = map { threads->create(\&act_busy) } 1 .. $n;

$_->join for @threads;

sub act_busy {
    for (1 .. 10_000_000) {
        my $x = 2 * 2;
    }
}

在我运行 Windows XP 的双核笔记本电脑上:

C:\> timethis t.pl 1
TimeThis : 经过的时间 : 00:00:02.375
C:\> timethis t.pl 2
TimeThis : 经过的时间 : 00:00:02.515
C:\> timethis t.pl 3
TimeThis : 经过的时间 : 00:00:03.734
C:\> timethis t.pl 4
TimeThis:经过的时间:00:00:04.703
...
C:\> timethis t.pl 10
TimeThis:经过的时间:00:00:11.703

现在,比较一下:

#!/usr/bin/perl

use strict; use warnings;

my ($n) = @ARGV;

act_busy() for 1 .. $n;

sub act_busy {
    for (1 .. 10_000_000) {
        my $x = 2 * 2;
    }
}
C:\> timethis s.pl 10
TimeThis : 经过时间 : 00:00:22.312

【讨论】:

  • 是的!这就是我要找的!我目前使用的 CPU 不超过一个,但我可以使用更多。因此,要使这种线程技术起作用,我必须拥有多个 cpu 吗? PDL 非常重视这比 for 循环更省时。没有说明 CPU 的数量。
  • 如果一个或多个线程在 IO 上花费大量时间阻塞,使用线程也可以提高整体执行时间,但我对您的问题的具体情况了解不多,无法评论它。最终,如果您只有一个 CPU/内核,那么在任何给定时间片内只能运行一个程序。
【解决方案2】:

正如 Sinan 所说,您可能想到的“线程”是“PDL 线程”,现在(从 2.075 开始)重命名为“广播”以匹配通用术语(请参阅 docs)。它允许您替换如下内容:

$x = sequence(5);
$x->set($_, $x->at($_)+2) for 0..$x->dim(0)-1;

只有这样,因为“+=”基本上只作用于一件事(零维标量),所以它可以“广播”比标量更多的维度(例如这个一维序列):

$x += 2; # does whole ndarray at once

这也更快,因为与for 循环不同,它不必不断离开和重新进入 Perl 环境(又名“Perl-land”),但可以保持在极快的“C-land”中无需开销即可进行计算。

其原名背后的动机是这些“广播”计算都是独立的,因此“尴尬地并行”,因此可以自动并行化。请参阅doc - 从 2.059 开始,PDL 默认设置为根据可用的 CPU 内核数量自动进行并行处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多