【问题标题】:how to convert a nested for loop into multithreading program in perl如何在perl中将嵌套的for循环转换为多线程程序
【发布时间】:2014-12-11 20:19:23
【问题描述】:

我需要帮助将嵌套的 for 循环转换为 Perl 中的多线程程序,例如

for ( my $i=0; $i<100; $i++) {
    for ( my $j=0; $j<100; $j++ ) {
         for ( my $k=0; $k<100; $k++ ) { 
             #do something ....                 
         } 
     }
 }

有没有办法可以将第一个循环拆分如下并并行运行

#Job1: 
for ( my $i=0; $i < 40; $i++) {
    for( my $j=0; $j < 100; $j++) {
        for( my $k=0; $k < 100; $k++) {
            #do something ....
         }
     }
 }

#Job2: 
for ( my $i=40; $i < 80; $i++) {
    for( my $j=0; $j<100; $j++) {
        for( my $k=0; $k<100; $k++) {
            #do something ....
         }
     }
 }

#Job3
for ( my $i=80; $i < 100; $i++) {
    for( my $j=0; $j < 100; $j++) {
        for( my $k=0; $k < 100; $k++) {
            #do something ....
         }
     }
 }

如何才能并行运行每个程序,然后只有当所有子程序Job1,Job2和job3都完成时才退出主程序。

【问题讨论】:

  • 循环执行块是否相互依赖?还是顺序无关紧要?即,如果您在 i=3 的块之前执行 i=5 的块,这对您来说很重要还是一样?这个问题直接影响解决方案
  • 我会选择Parallel::ForkManager,因为这看起来隐含并行。
  • 我可以按任何顺序运行循环,只有它们应该成功运行,然后只有主程序应该退出

标签: multithreading perl


【解决方案1】:

我将提供一个我以前使用过的similar answer 的参考 - 他们的关键问题是 - 你的工作完全解耦了吗?例如。没有数据需要在它们之间移动?

如果是这样,请使用Parallel::ForkManager 它有点像这样:

use Parallel::ForkManager;
my $fork_manager = Parallel::ForkManager -> new ( 10 ); #10 in parallel

for ( my $i=0;$i<100;$i++) {
    #in parallel:
    $fork_manager -> start and next;
    for ( my $j=0; $j < 100; $j++) {
         for ( my $k=0; $k < 100; $k++) { 
             #do something ....
         }
    }
    $fork_manager -> finish;
}
$fork_manager -> wait_all_children();

这将为$i 的每次迭代分叉代码并并行运行 - 而ForkManager 会将并发限制为 10。

这个数字应该与并行度的限制因素大致相当 - 如果是 CPU,那么 CPU 的数量,但请记住,您通常更受磁盘 IO 的限制。

进行并行处理时的主要注意事项:

  • 你不能保证执行顺序而不乱搞。循环$i==1 完全有可能在循环$i==2 之后完成。或者之前。管他呢。

  • 如果您在循环之间传递信息,并行会降低效率 - 因为发送方和接收方都需要同步。如果您需要同步整个批次,情况会更糟,因此请尽量避免不必要地这样做。 (例如,尽可能将其保留到最后并整理结果)。

  • 对于分叉代码来说,这是双倍的——它们是独立的进程,因此您实际上必须尝试来回传输内容。

  • 由于第一点,您可以从并行代码中得到一些非常有成果的错误。单独的代码行可能以任何顺序出现,因此可能会发生非常奇怪的事情。每个进程都会排序,但多个可能会交错。像open ( my $file, "&gt;&gt;", $output_filename ); 这样无害的东西会让你绊倒。

  • 分叉在分叉之间共享数据的能力非常有限。如果您需要做很多事情,请考虑使用线程。

线程是并发的另一种模型,在某些情况下可能很有价值。我通常倾向于forking 通常“更好”,但在我想要进行相当多的进程间通信的地方,我倾向于更多地关注threadsPerl daemonize with child daemons

【讨论】:

  • 上面会运行 10 个实例,i 值从 1 到 100,如果我想拆分循环以使每个作业实例以值 1 到 10、10 到 20、20 到 30 运行怎么办? , 30 到 40 ... 到 100。
  • 每次迭代都会启动一个实例。所以最初 - 10个工作,1..10。当其中一个完成时,它将从 11 开始。这样您就可以按顺序完成它们,但总是同时有 10 个。如果您真的想将它们分开,那么每个叉子都可以执行 1..10、11..20 等,但您需要更改循环。我会质疑你为什么需要打扰,因为创建分叉进程是有效的。
猜你喜欢
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
  • 2012-11-06
  • 2019-04-14
  • 1970-01-01
  • 2017-08-08
  • 2021-09-16
  • 1970-01-01
相关资源
最近更新 更多