1

現在、時間のかかるシミュレーションを効率的に実行することに行き詰まっています。シングル スレッド アプリケーションとクアッド コア システムであるため、4 つのシミュレーションを並行して実行することを目的としています。シェルスクリプトのバリエーションが必要です:

./sim -r 1 &
./sim -r 2 &
./sim -r 3 &
./sim -r 4 &
wait
./sim -r 5 &
./sim -r 6 &
./sim -r 7 &
./sim -r 8 &
wait
... (another 112 jobs) 

このコードでは、何度も待機します。また、タスクを 4 つのスクリプトに分割してそれぞれを実行しようとしましたが、その結果、1 つのスクリプトが終了し、残りのジョブの約 30% が残ります。シミュレーションにかかる時間は予測できません。

いつでも 4 つのシミュレーションを実行するための提案はありますか?

4

3 に答える 3

5

moreutilsパッケージを Ubuntu にインストールしてから、parallelユーティリティを使用します。

parallel -j 4 ./sim -r -- 1 2 3 4 5 6 7 8 ...
于 2013-11-02T22:33:25.963 に答える
2
NUMJOBS=30
NUMPOOLS=4

seq 1 "$NUMJOBS" | for p in $(seq 1 $NUMPOOLS); do
    while read x; do ./sim -r "$x"; done &
done

forループは、共有標準入力から読み取ってシミュレーションを開始するバックグラウンド プロセスのプールを作成します。各バックグラウンド プロセスは、シミュレーションの実行中に「ブロック」され、seqコマンドから次のジョブ番号を読み取ります。

ループがなければ、for従うのが少し簡単になるかもしれません:

seq 1 "$NUMJOBS" | {
    while read x; do ./sim -r "$x"; done &
    while read x; do ./sim -r "$x"; done &
    while read x; do ./sim -r "$x"; done &
    while read x; do ./sim -r "$x"; done &
}

sim実行にかなりの時間がかかると仮定すると、最初のループはwhile標準入力から 1 を読み取り、2 番目のループは 2 などを読み取ります。どちらがsim先に終了しても、そのwhileループはread標準入力から 5 を読み取ります。次に終了するものは 6 などになります。最後のシミュレーションが開始されると、それぞれreadが失敗し、ループが終了します。

于 2013-11-04T14:03:06.803 に答える
2

ユーティリティをインストールしたくない場合parallel(示されているように機能することを前提とすればきれいに見えます)、この Perl スクリプトを適応させ (基本的に、実行されるコマンドを変更します)、おそらく監視を減らすことができます:

#!/usr/bin/env perl
use strict;
use warnings;
use constant MAX_KIDS => 4;

$| = 1;

my %pids;
my $kids = 0;   # Number of kids

for my $i (1..20)
{
    my $pid;
    if (($pid = fork()) == 0)
    {
        my $tm = int(rand() * (10 - 2) + 2);
        print "sleep $tm\n";
        # Using exec in a block on its own is the documented way to
        # avoid the warning:
        # Statement unlikely to be reached at filename.pl line NN.
        #   (Maybe you meant system() when you said exec()?)
        # Yes, I know the print and exit statements should never be
        # reached, but, dammit, sometimes things go wrong!
        { exec "sleep", $tm; }
        print STDERR "Oops: couldn't sleep $tm!\n";
        exit 1;
    }
    $pids{$pid} = 1;
    $kids++;
    my $time = time;
    print "PID: $pid; Kids: $kids; Time: $time\n";
    if ($kids >= MAX_KIDS)
    {
        my $kid = waitpid(-1, 0);
        print "Kid: $kid ($?)\n";
        if ($kid != -1)
        {
            delete $pids{$kid};
            $kids--;
        }
    }
}

while ((my $kid = waitpid(-1, 0)) > 0)
{
    my $time = time;
    print "Kid: $kid (Status: $?); Time: $time\n";
    delete $pids{$kid};
    $kids--;
}

# This should not do anything - and doesn't (any more!).
foreach my $pid (keys %pids)
{
    printf "Undead: $pid\n";
}

出力例:

PID: 20152; Kids: 1; Time: 1383436882
PID: 20153; Kids: 2; Time: 1383436882
sleep 5
PID: 20154; Kids: 3; Time: 1383436882
sleep 7
sleep 9
PID: 20155; Kids: 4; Time: 1383436882
sleep 4
Kid: 20155 (0)
PID: 20156; Kids: 4; Time: 1383436886
sleep 4
Kid: 20152 (0)
PID: 20157; Kids: 4; Time: 1383436887
sleep 2
Kid: 20153 (0)
PID: 20158; Kids: 4; Time: 1383436889
sleep 9
Kid: 20157 (0)
PID: 20159; Kids: 4; Time: 1383436889
sleep 6
Kid: 20156 (0)
PID: 20160; Kids: 4; Time: 1383436890
sleep 6
Kid: 20154 (0)
PID: 20161; Kids: 4; Time: 1383436891
sleep 9
Kid: 20159 (0)
PID: 20162; Kids: 4; Time: 1383436895
sleep 7
Kid: 20160 (0)
PID: 20163; Kids: 4; Time: 1383436896
sleep 9
Kid: 20158 (0)
PID: 20164; Kids: 4; Time: 1383436898
sleep 6
Kid: 20161 (0)
PID: 20165; Kids: 4; Time: 1383436900
sleep 9
Kid: 20162 (0)
PID: 20166; Kids: 4; Time: 1383436902
sleep 9
Kid: 20164 (0)
PID: 20167; Kids: 4; Time: 1383436904
sleep 2
Kid: 20163 (0)
PID: 20168; Kids: 4; Time: 1383436905
sleep 6
Kid: 20167 (0)
PID: 20169; Kids: 4; Time: 1383436906
sleep 9
Kid: 20165 (0)
PID: 20170; Kids: 4; Time: 1383436909
sleep 4
Kid: 20168 (0)
PID: 20171; Kids: 4; Time: 1383436911
Kid: 20166 (0)
sleep 9
Kid: 20170 (Status: 0); Time: 1383436913
Kid: 20169 (Status: 0); Time: 1383436915
Kid: 20171 (Status: 0); Time: 1383436920
于 2013-11-03T00:04:49.650 に答える