【问题标题】:Run a script on multi cores and parallel processing在多核和并行处理上运行脚本
【发布时间】:2014-09-30 19:50:27
【问题描述】:

我正在编写一个从命令行获取一系列参数的脚本

script.pl start end 

for ($k1=$start; $k1<$end; $k1 += 0.001) {
  for ($k2=$start; $k2<$end; $k2 += 0.01) {
    for ($k3=$start; $k3<$end; $k3 += 0.001) {
      for ($k4=$start; $k4<$end; $k4 += 0.001) {
        for ($k5=$start; $k5<$end; $k5 += 0.001) {
...

}}}}}

如果我将参数设置在0到1之间,需要很长时间。最简单的方法是将它们分成更小的间隔,例如

script.pl 0 0.01 
script.pl 0.01 0.02
...
script.pl 0.9 1

那我要同时开100屏!!

有人可以指导我如何自动完成吗?

我不确定什么是最好的方法,因此我问。我有 256 个内核。

【问题讨论】:

  • 在同一台机器上一次打开 100 个屏幕并在它们上运行 100 个不同的脚本不会并行化任何事情。如果您的机器有 2 个内核,操作系统可能会在内核 1 上分配前 50 个脚本,在内核 2 上分配接下来的 50 个脚本
  • 您实际上想要完成什么?这看起来像很多嵌套迭代......但这并没有做任何事情。无论如何,perl 支持线程和分叉来执行并行代码。哪个最合适很大程度上取决于您要完成的工作。
  • 你有没有尝试过?您是否研究过用于跨内核分配工作的 perl 方法?鉴于您如何拆分它们的示例,解决方案是否不会呈现给您?是否提醒您可以使用 &amp; 从 shell 在后台运行脚本有帮助?
  • @arunmoezhi 这完全是并行化的。你甚至在评论中说了这么多。目前,据推测,他的脚本连续运行(并且在一个内核上运行,除非他显式或隐式地使用 perl 线程支持)。拆分它,如果存在的话,他保证能够使用多个核心(你自己也说过)。
  • 我想指出,打开 100 个屏幕并不能完成任何事情,而且并行化事情是一种痛苦的方式。正如您所说,使用 '&' 并在后台运行它会是一个更好的选择。如果脚本要运行很长时间,添加“nohup”也会很有用。

标签: linux perl shell


【解决方案1】:

查看并行代码时真正关键的问题是依赖关系。我将假设 - 因为你的脚本可以细分 - 你没有在循环内做任何复杂的事情。

但是,因为您步进了 0.001 和 5 个循环深度,所以如果您要从 0 到 1,那么您只是进行了很多次迭代。准确地说,是 100,000,000,000,000 次。

为了并行化,我个人建议您“展开”外部循环并使用Parallel::ForkManager

例如

my $CPU_count = 256;

my $fork_manager = Parallel::ForkManager->new($CPU_count);

for ( my $k1 = $start; $k1 < $end; $k1 += 0.001 ) {
    # Run outer loop in parallel
    my $pid = $fork_manager->start and next;

    for ( my $k2 = $start; $k2 < $end; $k2 += 0.01 ) {
        for ( my $k3 = $start; $k3 < $end; $k3 += 0.001 ) {
            for ( my $k4 = $start; $k4 < $end; $k4 += 0.001 ) {
                for ( my $k5 = $start; $k5 < $end; $k5 += 0.001 ) {
                    ...;
                }
            }
        }
    }

    $fork_manager->end;
}

这将做的是 - 对于该“外部”循环的每次迭代,分叉您的流程并将 4 个内部循环作为单独的流程运行。它将限制在 256 个并发进程。您应该将其与可用的 CPU 数量相匹配。

请记住 - 这仅适用于琐碎的“cpu 密集型”任务。如果您正在执行大量磁盘 IO 或尝试共享内存,那么这将无法正常工作。

另请注意 - 如果外部循环上的步骤数少于 CPU 的数量,它的并行性就不会那么好。

我还要注意 - $k2 有一个较小的迭代器。我已经从您的来源复制了它,但它可能是一个错字。

【讨论】:

  • 非常感谢。非常有帮助。 $k2 有一个较小的迭代器。没错
  • 我在文件中打印嵌套循环的输出时遇到了一个问题。我已经发布了 (stackoverflow.com/questions/26179647/…)。
  • 是的,使用 'fork()' 的缺点之一是在执行 IO 时会出现竞争条件。保存结果并将它们提供给“$k1.results”就可以了,因为每个分叉中的 $k1 都不同。但请记住,IO 通常是并行处理的限制因素。
【解决方案2】:

我不确定您的意思,但这将在后台并行启动 100 个作业。请注意,它可能会使您的计算机瘫痪,具体取决于您的硬件:

$ seq 0 0.02 0.99 | perl -lne 'print "$_ ",$_+0.01' | 
    while read start end; do script.pl $start $end; done; script.pl 0.99 1

这个想法是使用seq 生成间隔,通过一个打印出对的小perl 脚本进行管道传输。然后 bash 循环会读取这些内容,并使用相关参数启动脚本。

但是请注意,这远非实现目标的优雅方式。您可能想研究一下 GNU Parallel 或 Perl 本身可用的各种并行化工具。

【讨论】:

    【解决方案3】:

    terdon 答案的变体:

    paste <(seq -w 0 .01 1) <(seq -w 0.01 0.01 1.01) | xargs -n2 -P 255 ./script.pl
    

    将在下一个表单中启动 255 个并行进程

    ./script.pl 0.00 0.01
    ./script.pl 0.01 0.02
    ...
    ...
    ./script.pl 0.98 0.99
    ./script.pl 0.99 1.00
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多