2009-12-25 74 views
15

我是航空航天工程专业的学生,​​我正在做一个高级顶尖项目。我正在开发的数学模型之一需要XFOIL生成的天文数据量,XFOIL是一种流行的航空航天工具,用于查找翼型上的升力和阻力系数。 (但我正在离题)如何让我的Perl脚本为子进程使用多个内核?

切入正题:我有一个Perl脚本,它使用不同的输入参数反复调用XFOIL来生成我需要的数据。我需要XFOIL运行5600次,目前它每次运行平均需要大约100秒。做数学,这意味着它将需要大约6.5天才能完成。

现在,我有一个四核机器,但我作为程序员的经验是有限的,我真的只知道如何使用基本的Perl。我想一次运行4个XFOIL实例,都是在他们自己的核心上。事情是这样的:

while (1){ 
    for (i = 1..4){ 
     if (! exists XFOIL_instance(i)){ 
      start_new_XFOIL_instance(i, input_parameter_list); 
     } 
    } 
} 

所以在程序检查(或最好睡觉,直到XFOIL例如将其唤醒,开始一个新的实例),如果每一个内核的运行XFOIL。如果不是,则退出前一个实例,我们可以使用新的输入参数列表启动一个新实例。

如果任何人有任何想法如何实现,请让我知道。这将大大加快我需要生成数据的时间,并让我在航天项目本身上工作。

感谢您的帮助!

+1

我怕我不打算提供一个完整的答案,但短版是你可以肯定地分离当前perl脚本的四个实例,然后让每个实例运行一个XFOIL脚本。但是,为处理结果设置处理器亲和力 - 这将需要知道您正在使用的操作系统。 – 2009-12-25 18:53:16

+2

您确定XFOIL不会线程或以其他方式使用多个处理器,以使其运行时间首次达到大约100秒? – dlamblin 2009-12-25 19:18:05

+0

难以将XFOIL实现到C/Fortran中吗?如果不是,那么我建议你去做。 Perl并不完全是编程语言的Speedy Gonzalez ... – Zaid 2009-12-25 19:43:19

回答

17

尝试Parallel::ForkManager。这是一个模块,提供了一个简单的界面来分离这样的过程。

下面是一些示例代码:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Parallel::ForkManager; 

my @input_parameter_list = 
    map { join '_', ('param', $_) } 
    (1 .. 15); 

my $n_processes = 4; 
my $pm = Parallel::ForkManager->new($n_processes); 
for my $i (1 .. $n_processes) { 
    $pm->start and next; 

    my $count = 0; 
    foreach my $param_set (@input_parameter_list) {   
     $count++; 
     if (($count % $i) == 0) { 
      if (!output_exists($param_set)) { 
       start_new_XFOIL_instance($param_set); 
      } 
     } 
    } 

    $pm->finish; 
} 
$pm->wait_all_children; 

sub output_exists { 
    my $param_set = shift; 
    return (-f "$param_set.out"); 
} 

sub start_new_XFOIL_instance { 
    my $param_set = shift; 
    print "starting XFOIL instance with parameters $param_set!\n"; 
    sleep(5); 
    touch("$param_set.out"); 
    print "finished run with parameters $param_set!\n"; 
} 

sub touch { 
    my $fn = shift; 
    open FILE, ">$fn" or die $!; 
    close FILE or die $!; 
} 

您需要提供自己的实现为start_new_XFOIL_instance和output_exists功能,你还需要定义自己的参数集传递给XFOIL 。

+1

这看起来是我需要的。我将阅读Parallel :: ForkManager并让你知道它是如何发展的。谢谢您的帮助! 当然,任何其他来自其他任何输入的赞赏。 – 2009-12-25 20:10:55

+0

如果您还不知道,可以在主目录中安装Parallel :: ForkManager模块。看看这里如何做到这一点: http://stackoverflow.com/questions/540640/how-can-i-install-a-cpan-module-into-a-local-directory – 2009-12-26 06:30:19

+1

詹姆斯,非常感谢你的帮帮我。我通过命令行安装了Parallel :: ForkManager - 我想我现在已经开始运行了。我仍然试图弄清楚模块的复杂性以及我希望它在错误条件下的行为方式,但是在我的双核笔记本电脑上进行的初步运行让我认为我已经认识到了这一点 - 至少基本的想法,无论如何。再次感谢一堆! – 2009-12-26 07:55:57

3

这看起来像你可以使用齿轮工这个项目。

www.gearman.org

Gearman是一个工作队列。您可以将您的工作流程分成许多小部件。

我会推荐使用amazon.com甚至他们的拍卖能力服务器来完成这个项目。

每个计算小时或更少的时间花费10次,可以显着加速您的项目。

我会在本地使用gearman,确保你有一个“完美”的5-10你的subjobs运行之前,它交给一个亚马逊计算农场。

3

Perl threads将利用多个内核和处理器。线程的主要功能是在线程之间共享数据并协调其活动,这非常简单。分叉进程不能轻易将数据返回给父进程,也不能自行协调。

Perl线程的主要缺点是与fork相比创建起来相对昂贵,它们必须复制整个程序及其所有数据;你必须把它们编译到你的Perl中;他们可能是越野车,Perl越老,线程越脆弱。如果你的工作很昂贵,创作时间应该不重要。

下面是一个如何与线程一起使用的例子。有很多方法可以做到,这个使用Thread::Queue来创建工作线程可以共享的大量工作列表。当队列为空时,线程退出。主要优点是,它更容易控制有多少线程处于活动状态,并且您不必为每一项工作创建新的昂贵的线程。

本示例将所有工作一次性推送到队列中,但没有理由不能随时添加到队列中。如果你这样做,你会使用dequeue而不是dequeue_nb这将等待更多的输入。

use strict; 
use warnings; 

use threads; 
use Thread::Queue; 

# Dummy work routine 
sub start_XFOIL_instance { 
    my $arg = shift; 
    print "$arg\n"; 
    sleep 1; 
} 

# Read in dummy data 
my @xfoil_args = <DATA>; 
chomp @xfoil_args; 

# Create a queue to push work onto and the threads to pull work from 
# Populate it with all the data up front so threads can finish when 
# the queue is exhausted. Makes things simpler. 
# See https://rt.cpan.org/Ticket/Display.html?id=79733 
my $queue = Thread::Queue->new(@xfoil_args); 

# Create a bunch of threads to do the work 
my @threads; 
for(1..4) { 
    push @threads, threads->create(sub { 
     # Pull work from the queue, don't wait if its empty 
     while(my $xfoil_args = $queue->dequeue_nb) { 
      # Do the work 
      start_XFOIL_instance($xfoil_args); 
     } 

     # Yell when the thread is done 
     print "Queue empty\n"; 
    }); 
} 

# Wait for threads to finish 
$_->join for @threads; 

__DATA__ 
blah 
foo 
bar 
baz 
biff 
whatever 
up 
down 
left 
right 
+0

我看到我以前的评论(或您之前的回答)已被删除,无论如何感谢您更新您的答案。 我很好奇,如果你确定线程可以利用多个内核和处理器,如果是的话,你是如何验证它的? 谢谢 =) – user454322 2012-09-19 02:31:10

+0

@ user454322看到您的评论后,我写了一个脚本来在一堆线程中执行无限循环,并在OS X上使用Activity Monitor查看所有四个内核正在被使用。你说的线程模型是每个真实线程的新的Perl解释器。以前,我在我的脑海中认为这一切都是在一个过程中模拟的。 – Schwern 2012-09-20 02:13:54

+0

我已经发布http://stackoverflow.com/questions/12536064/how-does-perls-threading-system-work,如果你有机会请看看。 – user454322 2012-09-21 18:23:10

0

您是否考虑牛羚并行parallel。 它可以让你用不同的输入运行你的程序的几个安装实例,并且当你的CPU核心开始可用时,它们就会填满你的CPU核心。它通常是实现简单任务并行化的一种非常简单有效的方法。

相关问题