การรันคำสั่งแบบขนานพร้อมกับ จำกัด จำนวนคำสั่งพร้อมกัน


23

ตามลำดับ: for i in {1..1000}; do do_something $i; done- ช้าเกินไป

แบบขนาน: for i in {1..1000}; do do_something $i& done- โหลดมากเกินไป

วิธีรันคำสั่งแบบขนาน แต่ไม่เกิน 20 อินสแตนซ์ต่อนาที

ตอนนี้มักจะใช้วิธีแฮ็for i in {1..1000}; do do_something $i& sleep 5; doneค แต่นี่ไม่ใช่ทางออกที่ดี

อัปเดต 2 : แปลงคำตอบที่ยอมรับเป็นสคริปต์: http://vi-server.org/vi/parallel

#!/bin/bash

NUM=$1; shift

if [ -z "$NUM" ]; then
    echo "Usage: parallel <number_of_tasks> command"
    echo "    Sets environment variable i from 1 to number_of_tasks"
    echo "    Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
    echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
    exit 1
fi

export CMD="$@";

true ${MAKEOPTS:="-j20"}

cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})

all: \${jobs}

\${jobs}:
        i=\$@ sh -c "\$\$CMD"
EOF

โปรดทราบว่าคุณต้องแทนที่ช่องว่าง 8 ช่องด้วย 2 แท็บก่อน "i =" เพื่อให้ใช้งานได้

คำตอบ:


15

GNU Parallelสร้างขึ้นเพื่อสิ่งนี้

seq 1 1000 | parallel -j20 do_something

มันยังสามารถเรียกใช้งานบนคอมพิวเตอร์ระยะไกล นี่คือตัวอย่างสำหรับการเข้ารหัส MP3 เป็น OGG อีกครั้งโดยใช้เซิร์ฟเวอร์ 2 และคอมพิวเตอร์ในระบบที่ทำงาน 1 งานต่อซีพียูคอร์:

parallel --trc {.}.ogg -j+0 -S server2,: \
     'mpg321 -w - {} | oggenc -q0 - -o {.}.ogg' ::: *.mp3

ชมวิดีโอแนะนำ GNU Parallel ได้ที่นี่:

http://www.youtube.com/watch?v=OpaiGYxkSuQ


ยังไม่รู้เกี่ยวกับ "moreutils" และมีเครื่องมือสำหรับงานนี้อยู่แล้ว มองและเปรียบเทียบ
วิ

1
สิ่งที่parallelมากกว่านั้นไม่ได้เป็น GNU Parallel และค่อนข้าง จำกัด ในตัวเลือก คำสั่งข้างต้นจะไม่ทำงานโดยขนานจาก moreutils
Ole Tange

1
อีกหนึ่งตัวเลือก: xargs --max-procs=20.
วิ

4

ไม่ใช่โซลูชันทุบตี แต่คุณควรใช้ Makefile อาจเป็น-lไปได้ว่าจะมีการโหลดสูงสุดไม่เกิน

NJOBS=1000

.PHONY = jobs
jobs = $(shell echo {1..$(NJOBS)})

all: $(jobs)

$(jobs):
    do_something $@

จากนั้นให้เริ่มงานครั้งละ 20 งาน

$ make -j20

หรือเริ่มงานให้มากที่สุดโดยไม่เกินภาระงาน 5

$ make -j -l5

ดูเหมือนว่าจะไม่ใช่วิธีแฮ็คตอนนี้
วิ

2
echo -e 'PHONY=jobs\njobs=$(shell echo {1..100000})\n\nall: ${jobs}\n\n${jobs}:\n\t\techo $@; sleep `echo $$RANDOM/6553 | bc -l`' | make -f - -j20ตอนนี้มันดูแฮ็คมากขึ้นอีกครั้ง
วิ

@vi: โอ้ฉัน ....
Benjamin Bannier

แปลงโซลูชันของคุณเป็นสคริปต์ ตอนนี้มันสามารถใช้งานได้อย่างง่ายดาย
วิ

2

การโพสต์สคริปต์ในคำถามด้วยการจัดรูปแบบ:

#!/bin/bash

NUM=$1; shift

if [ -z "$NUM" ]; then
    echo "Usage: parallel <number_of_tasks> command"
    echo "    Sets environment variable i from 1 to number_of_tasks"
    echo "    Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
    echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
    exit 1
fi

export CMD="$@";

true ${MAKEOPTS:="-j20"}

cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})

all: \${jobs}

\${jobs}:
        i=\$@ sh -c "\$\$CMD"
EOF

โปรดทราบว่าคุณต้องแทนที่ช่องว่าง 8 ช่องด้วย 2 แท็บก่อนหน้า "i ="


1

แนวคิดง่ายๆหนึ่งข้อ:

ตรวจสอบ i modulo 20 และดำเนินการคำสั่ง wait shell-command ก่อน do_something


มันจะรอให้ภารกิจปัจจุบันทั้งหมดเสร็จสมบูรณ์ (สร้าง sags ในจำนวนของพล็อตงาน) หรือรองานเฉพาะอย่างหนึ่งที่สามารถหยุดทำงานได้นานขึ้น (สร้าง sags อีกครั้งในกรณีนี้)
Vi

@Vi: การรอของเชลล์สำหรับงานพื้นหลังทั้งหมดที่เป็นของเชลล์นี้
harrymc

1

คุณสามารถใช้psเพื่อนับจำนวนกระบวนการที่คุณใช้และเมื่อใดก็ตามที่สิ่งนี้มีค่าลดลงต่ำกว่าเกณฑ์ที่กำหนดคุณจะเริ่มกระบวนการอื่น

รหัสหลอก:

i = 1
MAX_PROCESSES=20
NUM_TASKS=1000
do
  get num_processes using ps
  if num_processes < MAX_PROCESSES
    start process $i
    $i = $i + 1
  endif
  sleep 1 # add this to prevent thrashing with ps
until $i > NUM_TASKS

1
for i in {1..1000}; do 
     (echo $i ; sleep `expr $RANDOM % 5` ) &
     while [ `jobs | wc -l` -ge 20 ] ; do 
         sleep 1 
     done
done

อาจจะเป็นwhile [ `jobs | wc -l` -ge 20]; doอย่างไร
วิ

แน่นอน แต่ในตัวอย่างของฉันฉันต้องคำนวณnjobsสองครั้งและประสิทธิภาพค่อนข้างสำคัญในเชลล์สคริปที่เรียกใช้งาน sleep;
msw

ฉันหมายความว่าเวอร์ชันของคุณไม่ทำงานตามที่คาดไว้ ฉันเปลี่ยนsleep 1เป็นsleep 0.1และมันเริ่มเฉลี่ย njobs เป็น 40-50 แทนที่จะเป็น 20 ถ้ามีงานมากกว่า 20 งานที่เราต้องรอให้งานใด ๆ เสร็จไม่รอเพียง 1 วินาที
วิ

0

คุณสามารถทำได้เช่นนี้

threads=20
tempfifo=$PMS_HOME/$$.fifo

trap "exec 1000>&-;exec 1000<&-;exit 0" 2
mkfifo $tempfifo
exec 1000<>$tempfifo
rm -rf $tempfifo

for ((i=1; i<=$threads; i++))
do
    echo >&1000
done

for ((j=1; j<=1000; j++))
do
    read -u1000
    {
        echo $j
        echo >&1000
    } &
done

wait
echo "done!!!!!!!!!!"

ใช้ไพพ์ที่มีชื่อทุกครั้งมันจะรัน 20 เชลล์ย่อยในแบบคู่ขนาน

หวังว่ามันจะช่วย :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.