我正在研究一种数学模型,该模型使用XFOIL生成的数据,XFOIL是一种流行的航空航天工具,用于查找机翼上的升力和阻力系数。
我有一个Perl脚本,它使用不同的输入参数重复调用XFOIL,以生成我需要的数据。我需要XFOIL运行5,600次,每次运行大约100秒,结束6.5天即可完成。
我有一台四核机器,但我作为程序员的经验有限,我真的只知道如何使用基本的Perl。
我想一次运行四个XFOIL实例,所有这些实例都在自己的核心上。像这样:
while ( 1 ) {
for ( i = 1..4 ) {
if ( ! exists XFOIL_instance(i) ) {
start_new_XFOIL_instance(i, input_parameter_list);
}
}
}
因此,当我们可以使用新的输入参数列表启动新实例时,程序正在检查(或最好是休眠)直到XFOIL实例空闲。
答案 0 :(得分: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 :(得分:4)
这看起来你可以使用gearman来完成这个项目。
www.gearman.org
Gearman是一个工作队列。您可以将工作流程分成许多小部件。
我建议使用amazon.com甚至他们的拍卖服务器来完成这个项目。
每个计算小时或更短时间花费10美分,可以显着增加您的项目。
我会在本地使用gearman,确保你有5-10个subjobs的“完美”运行,然后交给亚马逊计算农场。
答案 2 :(得分:4)
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
答案 3 :(得分:0)
您是否考虑过gnu parallel parallel。 它允许您使用不同的输入和运行程序的多个安装实例 在CPU核心开始可用时填充它们。它通常是实现简单任务并行化的一种非常简单有效的方法。
答案 4 :(得分:0)
这已经过时了,但如果有人仍在寻找这个问题的合适答案,您可能需要考虑Perl Many-Core-Engine (MCE)