54

コードの一部をより効率的にしたいと考えています。複数のプロセスにフォークして、一度だけではなく一度に 50/100 回実行することを考えています。

例(疑似):

for line in file;
do 
foo;
foo2;
foo3;
done

これを for ループで複数回実行したいと思います。これはフォークで実行できることを知っています。それはこのように見えるでしょうか?

while(x <= 50)
parent(child pid)
{
   fork child()
}
child
{
   do 
   foo; foo2; foo3; 
   done
   return child_pid()
}

それとも、これについて間違った方法で考えていますか?

ありがとう!

4

8 に答える 8

57

bash スクリプト (非対話型) では、デフォルトで JOB CONTROL が無効になっているため、次のコマンドを実行できません: job、fg、および bg。

これが私にとってうまくいくものです:

#!/bin/sh

set -m # Enable Job Control

for i in `seq 30`; do # start 30 jobs in parallel
  sleep 3 &
done

# Wait for all parallel jobs to finish
while [ 1 ]; do fg 2> /dev/null; [ $? == 1 ] && break; done

最後の行では、"fg" を使用して、バックグラウンド ジョブをフォアグラウンドに移動します。これは、fg が 1 ($? == 1) を返すまでループで実行されます。これは、バックグラウンド ジョブがなくなったときに実行されます。

于 2010-09-04T20:50:11.570 に答える
30

fork私はbashでの明示的な呼び出しを知りません。& おそらくやりたいことは、バックグラウンドで実行したいコマンドに追加することです。&bashスクリプト内で定義した関数で使用することもできます。

do_something_with_line()
{
  line=$1
  foo
  foo2
  foo3
}

for line in file
do
  do_something_with_line $line &
done

編集:同時バックグラウンドプロセスの数を制限するには、次のようなものを試すことができます:

for line in file
do
  while [`jobs | wc -l` -ge 50 ]
  do
    sleep 5
  done
  do_something_with_line $line &
done
于 2009-09-21T17:32:36.470 に答える
22

プロセスが終了するまでブロックされるため、使用したくありませんwait。現在のプロセスが完了するまでステータスの更新を取得できないため、待機するプロセスが複数ある場合は理想的ではありません。kill -0私はこれにとを組み合わせて使用​​することを好みsleepます。

pids待機する の配列が与えられた場合、以下のwaitPids()関数を使用して、どの pid がまだ完了を保留しているかについて継続的なフィードバックを取得します。

declare -a pids
waitPids() {
    while [ ${#pids[@]} -ne 0 ]; do
        echo "Waiting for pids: ${pids[@]}"
        local range=$(eval echo {0..$((${#pids[@]}-1))})
        local i
        for i in $range; do
            if ! kill -0 ${pids[$i]} 2> /dev/null; then
                echo "Done -- ${pids[$i]}"
                unset pids[$i]
            fi
        done
        pids=("${pids[@]}") # Expunge nulls created by unset.
        sleep 1
    done
    echo "Done!"
}

pidsバックグラウンドでプロセスを開始すると、以下のユーティリティ関数を使用して、その pid をすぐに配列に追加します。

addPid() {
    local desc=$1
    local pid=$2
    echo "$desc -- $pid"
    pids=(${pids[@]} $pid)
}

使用方法を示すサンプルを次に示します。

for i in {2..5}; do
    sleep $i &
    addPid "Sleep for $i" $!
done
waitPids

フィードバックは次のようになります。

Sleep for 2 -- 36271
Sleep for 3 -- 36272
Sleep for 4 -- 36273
Sleep for 5 -- 36274
Waiting for pids: 36271 36272 36273 36274
Waiting for pids: 36271 36272 36273 36274
Waiting for pids: 36271 36272 36273 36274
Done -- 36271
Waiting for pids: 36272 36273 36274
Done -- 36272
Waiting for pids: 36273 36274
Done -- 36273
Waiting for pids: 36274
Done -- 36274
Done!
于 2014-11-05T12:07:26.280 に答える
20

GNU Parallel を使用すると、次のことができます。

cat file | parallel 'foo {}; foo2 {}; foo3 {}'

これにより、各 CPU コアで 1 つのジョブが実行されます。50 を実行するには、次のようにします。

cat file | parallel -j 50 'foo {}; foo2 {}; foo3 {}'

詳細については、紹介ビデオをご覧ください。

http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

于 2012-01-05T09:51:57.450 に答える
2

例を試してみましょう

for x in 1 2 3 ; do { echo a $x ; sleep 1 ; echo b $x ; } &  done ; sleep 10

そして、jobs何が実行されているかを確認するために使用します。

于 2009-09-21T17:23:57.247 に答える
2

皆さんが共有したことに基づいて、これをまとめることができました:

#!/usr/bin/env bash

VAR1="192.168.1.20 192.168.1.126 192.168.1.36"

for a in $VAR1; do { ssh -t -t $a -l Administrator "sudo softwareupdate -l"; } & done;
WAITPIDS="$WAITPIDS "$!;...; wait $WAITPIDS
echo "Script has finished"

Exit 1

これにより、一度に 3 台のマシンの Mac のすべての更新が一覧表示されます。後で、ipaddress.txt を CAT したときに、すべてのマシンのソフトウェア更新を実行するために使用しました。

于 2012-12-13T22:10:27.530 に答える
1

ここに私のスレッド制御関数があります:

#!/bin/bash
# This function just checks jobs in background, don't do more things.
# if jobs number is lower than MAX, then return to get more jobs;
# if jobs number is greater or equal to MAX, then wait, until someone finished.

# Usage:
#   thread_max 8
#   thread_max 0    # wait, until all jobs completed

thread_max() {
    local CHECK_INTERVAL="3s"
    local CUR_THREADS=
    local MAX=
    [[ $1 ]] && MAX=$1 || return 127

    # reset MAX value, 0 is easy to remember
    [ $MAX -eq 0 ] && {
        MAX=1
        DEBUG "waiting for all tasks finish"
    }

    while true; do
        CUR_THREADS=`jobs -p | wc -w`

        # workaround about jobs bug. If don't execute it explicitily,
        # CUR_THREADS will stick at 1, even no jobs running anymore.
        jobs &>/dev/null

        DEBUG "current thread amount: $CUR_THREADS"
        if [ $CUR_THREADS -ge $MAX ]; then
            sleep $CHECK_INTERVAL
        else
            return 0
        fi
    done
}
于 2013-12-04T16:08:21.273 に答える