2011-06-28 15 views
21

Câu hỏi của tôi là cách thay đổi mã này để nó chỉ sử dụng 4 luồng/tiến trình con?Làm thế nào để giới hạn số luồng/tiểu quy trình được sử dụng trong một hàm trong bash

TESTS="a b c d e" 

for f in $TESTS; do 
    t=$[ ($RANDOM % 5) + 1 ] 
    sleep $t && echo $f $t & 
done 
wait 
+15

Đây không phải là chủ đề, nhưng quá trình phụ. –

+2

Bạn có thể vui lòng xem xét chấp nhận câu trả lời và thay đổi "chủ đề" thành "các quy trình phụ" trong câu hỏi của bạn không? Sử dụng các từ sai khiến bạn khó tìm thấy trên web! ;-) – Peque

Trả lời

5

Bạn có thể làm một cái gì đó như thế này bằng cách sử dụng các jobs dựng sẵn:

for f in $TESTS; do 
    running=($(jobs -rp)) 
    while [ ${#running[@]} -ge 4 ] ; do 
    sleep 1 # this is not optimal, but you can't use wait here 
    running=($(jobs -rp)) 
    done 
    t=$[ ($RANDOM % 5) + 1 ] 
    sleep $t && echo $f $t & 
done 
wait 
0

kịch bản thử nghiệm này chạy 5 công việc tại một thời điểm và sẽ khởi động lại một công việc mới càng sớm càng nó (do giết chết của giấc ngủ 10,9 khi chúng tôi nhận được một SIGCHLD.Một phiên bản đơn giản của điều này có thể sử dụng trực tiếp bỏ phiếu (thay đổi giấc ngủ 10,9 để ngủ 1 và thoát khỏi cái bẫy)

#!/usr/bin/bash 

set -o monitor 
trap "pkill -P $$ -f 'sleep 10\.9' >&/dev/null" SIGCHLD 

totaljobs=15 
numjobs=5 
worktime=10 
curjobs=0 
declare -A pidlist 

dojob() 
{ 
    slot=$1 
    time=$(echo "$RANDOM * 10/32768" | bc -l) 
    echo Starting job $slot with args $time 
    sleep $time & 
    pidlist[$slot]=`jobs -p %%` 
    curjobs=$(($curjobs + 1)) 
    totaljobs=$(($totaljobs - 1)) 
} 

# start 
while [ $curjobs -lt $numjobs -a $totaljobs -gt 0 ] 
do 
    dojob $curjobs 
done 

# Poll for jobs to die, restarting while we have them 
while [ $totaljobs -gt 0 ] 
do 
    for ((i=0;$i < $curjobs;i++)) 
    do 
    if ! kill -0 ${pidlist[$i]} >&/dev/null 
    then 
     dojob $i 
     break 
    fi 
    done 
    sleep 10.9 >&/dev/null 
done 
wait 
32

Thú vị questi trên. Tôi đã cố gắng sử dụng xargs cho điều này và tôi tìm thấy một cách.

Hãy thử điều này:

seq 10 | xargs -i --max-procs=4 bash -c "echo start {}; sleep 3; echo done {}" 

--max-procs=4 sẽ đảm bảo rằng không quá bốn subprocesses đang chạy tại một thời điểm.

Đầu ra sẽ trông như thế này:

start 2 
start 3 
start 1 
start 4 
done 2 
done 3 
done 1 
done 4 
start 6 
start 5 
start 7 
start 8 
done 6 
done 5 
start 9 
done 8 
done 7 
start 10 
done 9 
done 10 

Lưu ý rằng thứ tự thực hiện có thể không làm theo các lệnh theo thứ tự bạn gửi cho họ. Như bạn có thể thấy 2 bắt đầu trước 1.

13

giải pháp nhanh chóng và bẩn: chèn dòng này ở đâu đó bên trong for vòng lặp của bạn:

while [ $(jobs | wc -l) -ge 4 ] ; do sleep 1 ; done 

(giả định bạn chưa có việc làm nền khác chạy trong cùng một vỏ)

+4

điều này có thể là một chút rất hiệu quả hơn với 'jobs -r' - không có nó, bạn sẽ đếm các dòng nơi bash cho bạn biết công việc nào đã được thực hiện. – Mat

+0

Giải pháp này rất tuyệt. Tôi chỉ cần chèn các dòng ở đúng nơi và bùng nổ! Tôi thích rằng tôi không cần phải thay đổi cấu trúc tập lệnh của mình –

7

tôi đã tìm thấy một giải pháp cho câu hỏi này sử dụng parallel (một phần của moreutils gói.)

parallel -j 4 -i bash -c "echo start {}; sleep 2; echo done {};" -- $(seq 10) 

-j 4 đứng cho -j maxjobs

-i sử dụng các thông số như {}

-- delimits lập luận của bạn

Kết quả của lệnh này sẽ là:

start 3 
start 4 
start 1 
start 2 
done 4 
done 2 
done 3 
done 1 
start 5 
start 6 
start 7 
start 8 
done 5 
done 6 
start 9 
done 7 
start 10 
done 8 
done 9 
done 10 
3

GNU Parallel được thiết kế cho các loại hình nhiệm vụ:

TESTS="a b c d e" 
for f in $TESTS; do 
    t=$[ ($RANDOM % 5) + 1 ] 
    sem -j4 sleep $t && echo $f $t 
done 
sem --wait 

Watch video giới thiệu để tìm hiểu thêm:

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

Các vấn đề liên quan