คุณรันหลายโปรแกรมพร้อมกันจาก bash script ได้อย่างไร


245

ฉันพยายามเขียนไฟล์. shที่รันหลายโปรแกรมพร้อมกัน

ฉันลองสิ่งนี้

prog1 
prog2

แต่นั่นจะทำงาน prog1 จากนั้นรอจนกว่า prog1 จะสิ้นสุดลงและจากนั้นเริ่ม prog2 ...

ดังนั้นฉันจะเรียกใช้พวกเขาในแบบคู่ขนานได้อย่างไร

คำตอบ:


216
prog1 &
prog2 &

49
อย่าลืมwait! ใช่ในทุบตีคุณสามารถรอกระบวนการลูกของสคริปต์
Dummy00001

5
อีกทางเลือกหนึ่งคือการใช้nohupเพื่อป้องกันไม่ให้โปรแกรมถูกฆ่าเมื่อเชลล์วางสาย
ฟิลิปป์

@liang: ใช่มันจะทำงานกับสามโปรแกรมขึ้นไปด้วย
psmears

302

เกี่ยวกับ:

prog1 & prog2 && fg

นี่จะ:

  1. prog1เริ่มต้น
  2. ส่งไปที่พื้นหลัง แต่พิมพ์งานต่อไป
  3. เริ่มต้นprog2และเก็บไว้ในเบื้องหน้าctrl-cเพื่อให้คุณสามารถปิดมันด้วย
  4. เมื่อคุณอยู่ใกล้prog2คุณจะกลับไปprog1's เบื้องหน้าctrl-cเพื่อให้คุณสามารถยังอยู่ใกล้กับ

9
มีวิธีง่าย ๆ ในการยกเลิกprog1เมื่อprog2ยกเลิกหรือไม่ คิดว่า node srv.js & cucumberjs
JP

20
เพิ่งลองสิ่งนี้และมันก็ไม่ได้ผลอย่างที่คาดไว้สำหรับฉัน อย่างไรก็ตามการแก้ไขเล็กน้อยทำงาน: prog1 & prog2 ; fg นี่คือการใช้อุโมงค์หลาย ssh ในครั้งเดียว หวังว่านี่จะช่วยใครซักคน
jnadro52

2
@ jnadro52 โซลูชันของคุณมีผลกระทบที่หากprog2ไม่สามารถทำงานได้ทันทีคุณจะกลับมามีprog1ส่วนร่วมในเบื้องหน้า หากสิ่งนี้เป็นที่พึงปรารถนาแสดงว่าไม่เป็นไร
วง Ory

3
บนเชลล์ SSH'ed หากคุณเรียกใช้คำสั่งเช่นนี้จะเป็นการยากที่จะฆ่า prog1 Ctrl-c ไม่ทำงานสำหรับฉัน แม้แต่การฆ่าเทอร์มินัลทั้งหมดก็ยังคงทำงานอยู่
mercury0114

14
@ jnadro52 prog1 & prog2 && kill $!วิธีที่จะยุติกระบวนการทั้งสองครั้งคือ
zaboco

79

คุณสามารถใช้wait:

some_command &
P1=$!
other_command &
P2=$!
wait $P1 $P2

มันกำหนด PID โปรแกรมพื้นหลังให้กับตัวแปร ( $!เป็นกระบวนการเปิดตัวล่าสุด 'PID) จากนั้นwaitคำสั่งจะรอให้พวกเขา เป็นเรื่องที่ดีเพราะถ้าคุณฆ่าสคริปต์มันจะฆ่ากระบวนการด้วย!


4
จากประสบการณ์ของฉันการรอฆ่าไม่ได้ฆ่ากระบวนการอื่นด้วย
Quinn

1
หากฉันกำลังเริ่มกระบวนการพื้นหลังในลูปฉันจะรอให้กระบวนการส่วนหลังดำเนินการจนเสร็จสิ้นก่อนที่จะดำเนินการต่อด้วยการดำเนินการคำสั่งชุดถัดไป #!/usr/bin/env bash ARRAY='cat bat rat' for ARR in $ARRAY do ./run_script1 $ARR & done P1=$! wait $P1 echo "INFO: Execution of all background processes in the for loop has completed.."
Yash

@Yash ฉันคิดว่าคุณสามารถบันทึก ID กระบวนการลงในอาเรย์แล้วโทรไปที่อาเรย์ ฉันคิดว่าคุณต้องใช้${}เพื่อสอดแทรกเข้าไปในรายการสตริงหรือคล้ายกัน
trusktr

คำตอบที่ดีที่สุดและสำหรับฉันที่ฆ่าสคริปต์ก็ฆ่ากระบวนการด้วยเช่นกัน! macOS Catalina, คอนโซล zsh
Michael Klishevich

67

ด้วย GNU Parallel http://www.gnu.org/software/parallel/มันง่ายเหมือน:

(echo prog1; echo prog2) | parallel

หรือถ้าคุณต้องการ:

parallel ::: prog1 prog2

เรียนรู้เพิ่มเติม:

  • ชมวิดีโอแนะนำสำหรับการแนะนำอย่างรวดเร็ว: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
  • เดินผ่านบทช่วยสอน (ผู้ชาย parallel_tutorial) บรรทัดคำสั่งของคุณจะรักคุณ
  • อ่าน: Ole Tange, GNU Parallel 2018 (Ole Tange, 2018)

4
เป็นที่น่าสังเกตว่ามีเวอร์ชันต่าง ๆ ที่parallelมีไวยากรณ์ต่างกัน ตัวอย่างเช่นบน Debian Derivatives moreutilsแพคเกจประกอบด้วยคำสั่งต่าง ๆ ที่เรียกว่าparallelซึ่งมีพฤติกรรมแตกต่างกันมาก
Joel Cross

4
เป็นparallelดีกว่าการใช้&?
Optimus Prime

2
@OptimusPrime มันขึ้นอยู่กับมันจริงๆ GNU Parallel นำเสนอค่าใช้จ่ายบางส่วน แต่ในทางกลับกันจะช่วยให้คุณควบคุมงานและเอาต์พุตที่กำลังทำงานอยู่ได้มากขึ้น หากพิมพ์งานสองงานในเวลาเดียวกัน GNU Parallel จะทำให้แน่ใจว่างานพิมพ์ไม่ได้ปะปนกัน
Ole Tange

1
@OptimusPrime parallelดีกว่าเมื่อมีงานมากกว่าคอร์ซึ่งในกรณีนี้&จะทำงานมากกว่าหนึ่งงานต่อคอร์ในครั้งเดียว ( หลักหลักการเทียบนกพิราบ )
Geremia

2
@OleTange " บรรทัดคำสั่งของคุณจะรักคุณ " Me เช่นกัน ☺
Geremia

55

หากคุณต้องการที่จะสามารถเรียกใช้และฆ่าหลาย ๆ โพรเซสได้อย่างง่ายดายctrl-cนี่คือวิธีที่ฉันชอบ: วางไข่กระบวนการพื้นหลังหลาย ๆ อันใน(…)subshell และกับดักSIGINTเพื่อดำเนินการkill 0ซึ่งจะฆ่าทุกอย่างที่เกิดในกลุ่ม subshell:

(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)

คุณสามารถมีโครงสร้างการดำเนินการกระบวนการที่ซับซ้อนและทุกอย่างจะปิดเพียงครั้งเดียวctrl-c(ตรวจสอบให้แน่ใจว่ากระบวนการสุดท้ายทำงานในเบื้องหน้าคือไม่รวม&หลังprog1.3)

(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)

นี่คือคำตอบที่ดีที่สุด
Nic

10

xargs -P <n>ช่วยให้คุณสามารถรัน<n>คำสั่งแบบขนาน

ในขณะที่-Pเป็นตัวเลือกที่ไม่เป็นมาตรฐานทั้งการใช้งาน GNU (Linux) และ macOS / BSD รองรับ

ตัวอย่างต่อไปนี้:

  • รันได้สูงสุด 3 คำสั่งพร้อมกันในแต่ละครั้ง
  • ด้วยคำสั่งเพิ่มเติมเริ่มต้นเฉพาะเมื่อกระบวนการที่เปิดตัวก่อนหน้านี้ถูกยกเลิก
time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF

ผลลัพธ์ดูเหมือนว่า:

1   # output from 1st command 
4   # output from *last* command, which started as soon as the count dropped below 3
2   # output from 2nd command
3   # output from 3rd command

real    0m3.012s
user    0m0.011s
sys 0m0.008s

เวลาแสดงให้เห็นว่าคำสั่งถูกเรียกใช้ในแบบขนาน (คำสั่งสุดท้ายถูกเปิดใช้เฉพาะหลังจากที่ยกเลิกครั้งแรกของ 3 ต้นฉบับ แต่ดำเนินการอย่างรวดเร็ว)

xargsคำสั่งตัวเองจะไม่กลับมาจนกว่าคำสั่งทั้งหมดได้เสร็จสิ้น แต่คุณสามารถดำเนินการได้ในพื้นหลังโดยยกเลิกกับผู้ประกอบการการควบคุม&และจากนั้นใช้waitbuiltin รอให้ทั้งxargsคำสั่งให้เสร็จ

{
  xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &

# Script execution continues here while `xargs` is running 
# in the background.
echo "Waiting for commands to finish..."

# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!

บันทึก:

  • BSD / macOS xargsต้องการให้คุณระบุจำนวนคำสั่งเพื่อให้ทำงานแบบขนานอย่างชัดเจนในขณะที่ GNU xargsอนุญาตให้คุณระบุ-P 0ให้ทำงานมากที่สุดในแบบขนาน

  • ออกจากกระบวนการทำงานแบบขนานมาถึงขณะที่มันจะถูกสร้างขึ้นจึงจะได้รับการบรรณนิทัศน์อันเป็น

    • GNU parallelดังที่ได้กล่าวไว้ในคำตอบของ Ole (ไม่ได้มาพร้อมกับแพลตฟอร์มส่วนใหญ่) ทำให้เป็นอนุกรม (กลุ่ม) เอาท์พุทสิ่งอำนวยความสะดวกแบบต่อกระบวนการและเสนอคุณสมบัติขั้นสูงอื่น ๆ อีกมากมาย

9
#!/bin/bash
prog1 & 2> .errorprog1.log; prog2 & 2> .errorprog2.log

เปลี่ยนเส้นทางข้อผิดพลาดเพื่อแยกบันทึก


13
คุณต้องใส่เครื่องหมายแอมเปอร์แซนด์หลังการเปลี่ยนเส้นทางและเว้นเครื่องหมายอัฒภาค (แอมเปอร์แซนด์จะทำหน้าที่ของตัวคั่นคำสั่งด้วย):prog1 2> .errorprog1.log & prog2 2> .errorprog2.log &
หยุดชั่วคราวจนกว่าจะมีประกาศเพิ่มเติม

เครื่องหมายอัฒภาครันทั้ง comands คุณสามารถทดสอบ de bash เพื่อดูว่าทำงานได้ดี;) ตัวอย่าง: pwd & 2> .errorprog1.log; echo "wop" & 2> .errorprog2.log เมื่อคุณใส่ & คุณใส่โปรแกรมในพื้นหลังและดำเนินการคำสั่งถัดไปทันที
fermin

2
ไม่ทำงาน - ข้อผิดพลาดจะไม่ถูกเปลี่ยนเส้นทางไปยังไฟล์ ls notthere1 & 2> .errorprog1.log; ls notthere2 & 2>.errorprog2.logลองด้วย: ข้อผิดพลาดไปที่คอนโซลและไฟล์ข้อผิดพลาดทั้งสองนั้นว่างเปล่า ในฐานะที่เป็น @Dennis Williamson พูดว่า&เป็นตัวคั่น;ดังนั้น (ก) จะต้องไปที่จุดสิ้นสุดของคำสั่ง (หลังจากการเปลี่ยนเส้นทาง) และ (b) คุณไม่จำเป็นต้องใช้;:-) ทั้งหมด
psmears

8

มีโปรแกรมที่มีประโยชน์มากที่เรียกว่า nohup

     nohup - run a command immune to hangups, with output to a non-tty

4
nohupด้วยตัวเองไม่ได้ทำงานอะไรในพื้นหลังและการใช้nohupไม่ใช่ข้อกำหนดหรือข้อกำหนดเบื้องต้นสำหรับการทำงานในพื้นหลัง พวกเขามักจะมีประโยชน์ร่วมกัน แต่เป็นเช่นนี้ไม่ตอบคำถาม
tripleee

8

นี่คือฟังก์ชั่นที่ฉันใช้เพื่อเรียกใช้ที่กระบวนการ max n แบบขนาน (n = 4 ในตัวอย่าง):

max_children=4

function parallel {
  local time1=$(date +"%H:%M:%S")
  local time2=""

  # for the sake of the example, I'm using $2 as a description, you may be interested in other description
  echo "starting $2 ($time1)..."
  "$@" && time2=$(date +"%H:%M:%S") && echo "finishing $2 ($time1 -- $time2)..." &

  local my_pid=$$
  local children=$(ps -eo ppid | grep -w $my_pid | wc -w)
  children=$((children-1))
  if [[ $children -ge $max_children ]]; then
    wait -n
  fi
}

parallel sleep 5
parallel sleep 6
parallel sleep 7
parallel sleep 8
parallel sleep 9
wait

หาก max_children ถูกตั้งค่าเป็นจำนวนแกนฟังก์ชั่นนี้จะพยายามหลีกเลี่ยงแกนกลางที่ไม่ได้ทำงาน


1
ตัวอย่างที่ดี แต่ฉันไม่สามารถหาคำอธิบายของ "wait -n" ภายใต้การทุบตีของฉันมันบอกว่ามันเป็นตัวเลือกที่ไม่ถูกต้อง พิมพ์ผิดหรือฉันคิดถึงอะไรบางอย่าง?
Emmanuel Devaux

1
@EmmanuelDevaux: wait -nต้องใช้bash4.3+และจะเปลี่ยนลอจิกเพื่อรอกระบวนการที่ระบุ / โดยนัยใด ๆที่จะยุติ
mklement0

จะทำอย่างไรถ้างานใดงานหนึ่งล้มเหลวฉันต้องการจบสคริปต์หรือไม่
52coder

@ 52coder คุณสามารถปรับฟังก์ชั่นเพื่อจับภาพเด็กที่ล้มเหลวได้เช่น: "$ @" && time2 = $ (วันที่ + "% H:% M:% S:) && echo" สิ้นสุด $ 2 ($ time1 - $ time2 ) ... "|| ข้อผิดพลาด = 1 & จากนั้นทดสอบสำหรับข้อผิดพลาดใน "ถ้า" และส่วนหนึ่งของฟังก์ชั่นการยกเลิกนั้นถ้าจำเป็น
arnaldocan

7

คุณสามารถลองppss ppss ค่อนข้างทรงพลัง - คุณสามารถสร้างมินิคลัสเตอร์ได้ xargs -P ยังมีประโยชน์ถ้าคุณมีชุดของการประมวลผลแบบขนานที่น่าอาย


7

ฉันมีสถานการณ์ที่คล้ายกันเมื่อเร็ว ๆ นี้ที่ฉันต้องการเรียกใช้หลายโปรแกรมในเวลาเดียวกันเปลี่ยนเส้นทางผลลัพธ์ของพวกเขาไปยังไฟล์บันทึกที่แยกจากกันและรอให้พวกเขาเสร็จสิ้นและฉันก็จบลงด้วยสิ่งดังนี้:

#!/bin/bash

# Add the full path processes to run to the array
PROCESSES_TO_RUN=("/home/joao/Code/test/prog_1/prog1" \
                  "/home/joao/Code/test/prog_2/prog2")
# You can keep adding processes to the array...

for i in ${PROCESSES_TO_RUN[@]}; do
    ${i%/*}/./${i##*/} > ${i}.log 2>&1 &
    # ${i%/*} -> Get folder name until the /
    # ${i##*/} -> Get the filename after the /
done

# Wait for the processes to finish
wait

ที่มา: http://joaoperibeiro.com/execute-multiple-programs-and-redirect-their-outputs-linux/


4

ผู้จัดการกระบวนการวางไข่

แน่นอนว่าทางเทคนิคคือกระบวนการและโปรแกรมนี้ควรเรียกว่าตัวจัดการการวางไข่จริงๆ แต่นี่เป็นเพียงวิธีการที่ BASH ทำงานเมื่อมันใช้ส้อมแอมเปอร์แซนด์โดยใช้ fork () หรือการเรียกระบบโคลน () ซึ่งโคลนลงในพื้นที่หน่วยความจำแยกต่างหากแทนที่จะเป็นอะไรเช่น pthread_create () ซึ่งจะแชร์หน่วยความจำ หาก BASH สนับสนุนหลัง "ลำดับของการดำเนินการ" แต่ละอันจะทำงานเหมือนกันและอาจเรียกว่าเป็นเธรดดั้งเดิมในขณะที่ได้รับหน่วยความจำที่มีประสิทธิภาพมากขึ้น อย่างไรก็ตามฟังก์ชั่นมันใช้งานได้เหมือนกันแม้ว่าจะยากขึ้นเล็กน้อยเนื่องจากตัวแปร GLOBAL ไม่สามารถใช้ได้ในแต่ละโคลนของผู้ปฏิบัติงานดังนั้นการใช้ไฟล์การสื่อสารระหว่างกระบวนการและเซมาฟอร์ขั้นต้นเพื่อจัดการส่วนที่สำคัญ แน่นอนว่าการตอบโต้จาก BASH นั้นเป็นคำตอบพื้นฐานที่นี่ แต่ฉันรู้สึกราวกับว่าผู้คนรู้ว่า แต่กำลังมองหาวิธีการจัดการสิ่งที่เกิดขึ้นจริง ๆ มากกว่าแค่แยกมันและลืมมันไป สิ่งนี้แสดงให้เห็นถึงวิธีการจัดการกระบวนการแบบแยกส่วนได้ถึง 200 อินสแตนซ์ทั้งหมดที่เข้าถึงทรัพยากรเดียว เห็นได้ชัดว่านี่เป็น overkill แต่ฉันสนุกกับการเขียนดังนั้นฉันจึงยังคง เพิ่มขนาดเทอร์มินัลของคุณตามลำดับ ฉันหวังว่าคุณจะพบว่ามีประโยชน์นี้

ME=$(basename $0)
IPC="/tmp/$ME.ipc"      #interprocess communication file (global thread accounting stats)
DBG=/tmp/$ME.log
echo 0 > $IPC           #initalize counter
F1=thread
SPAWNED=0
COMPLETE=0
SPAWN=1000              #number of jobs to process
SPEEDFACTOR=1           #dynamically compensates for execution time
THREADLIMIT=50          #maximum concurrent threads
TPS=1                   #threads per second delay
THREADCOUNT=0           #number of running threads
SCALE="scale=5"         #controls bc's precision
START=$(date +%s)       #whence we began
MAXTHREADDUR=6         #maximum thread life span - demo mode

LOWER=$[$THREADLIMIT*100*90/10000]   #90% worker utilization threshold
UPPER=$[$THREADLIMIT*100*95/10000]   #95% worker utilization threshold
DELTA=10                             #initial percent speed change

threadspeed()        #dynamically adjust spawn rate based on worker utilization
{
   #vaguely assumes thread execution average will be consistent
   THREADCOUNT=$(threadcount)
   if [ $THREADCOUNT -ge $LOWER ] && [ $THREADCOUNT -le $UPPER ] ;then
      echo SPEED HOLD >> $DBG
      return
   elif [ $THREADCOUNT -lt $LOWER ] ;then
      #if maxthread is free speed up
      SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1-($DELTA/100))"|bc)
      echo SPEED UP $DELTA%>> $DBG
   elif [ $THREADCOUNT -gt $UPPER ];then
      #if maxthread is active then slow down
      SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1+($DELTA/100))"|bc)
      DELTA=1                            #begin fine grain control
      echo SLOW DOWN $DELTA%>> $DBG
   fi

   echo SPEEDFACTOR $SPEEDFACTOR >> $DBG

   #average thread duration   (total elapsed time / number of threads completed)
   #if threads completed is zero (less than 100), default to maxdelay/2  maxthreads

   COMPLETE=$(cat $IPC)

   if [ -z $COMPLETE ];then
      echo BAD IPC READ ============================================== >> $DBG
      return
   fi

   #echo Threads COMPLETE $COMPLETE >> $DBG
   if [ $COMPLETE -lt 100 ];then
      AVGTHREAD=$(echo "$SCALE;$MAXTHREADDUR/2"|bc)
   else
      ELAPSED=$[$(date +%s)-$START]
      #echo Elapsed Time $ELAPSED >> $DBG
      AVGTHREAD=$(echo "$SCALE;$ELAPSED/$COMPLETE*$THREADLIMIT"|bc)
   fi
   echo AVGTHREAD Duration is $AVGTHREAD >> $DBG

   #calculate timing to achieve spawning each workers fast enough
   # to utilize threadlimit - average time it takes to complete one thread / max number of threads
   TPS=$(echo "$SCALE;($AVGTHREAD/$THREADLIMIT)*$SPEEDFACTOR"|bc)
   #TPS=$(echo "$SCALE;$AVGTHREAD/$THREADLIMIT"|bc)  # maintains pretty good
   #echo TPS $TPS >> $DBG

}
function plot()
{
   echo -en \\033[${2}\;${1}H

   if [ -n "$3" ];then
         if [[ $4 = "good" ]];then
            echo -en "\\033[1;32m"
         elif [[ $4 = "warn" ]];then
            echo -en "\\033[1;33m"
         elif [[ $4 = "fail" ]];then
            echo -en "\\033[1;31m"
         elif [[ $4 = "crit" ]];then
            echo -en "\\033[1;31;4m"
         fi
   fi
      echo -n "$3"
      echo -en "\\033[0;39m"
}

trackthread()   #displays thread status
{
   WORKERID=$1
   THREADID=$2
   ACTION=$3    #setactive | setfree | update
   AGE=$4

   TS=$(date +%s)

   COL=$[(($WORKERID-1)/50)*40]
   ROW=$[(($WORKERID-1)%50)+1]

   case $ACTION in
      "setactive" )
         touch /tmp/$ME.$F1$WORKERID  #redundant - see main loop
         #echo created file $ME.$F1$WORKERID >> $DBG
         plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID INIT    " good
         ;;
      "update" )
         plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID AGE:$AGE" warn
         ;;
      "setfree" )
         plot $COL $ROW "Worker$WORKERID: FREE                         " fail
         rm /tmp/$ME.$F1$WORKERID
         ;;
      * )

      ;;
   esac
}

getfreeworkerid()
{
   for i in $(seq 1 $[$THREADLIMIT+1])
   do
      if [ ! -e /tmp/$ME.$F1$i ];then
         #echo "getfreeworkerid returned $i" >> $DBG
         break
      fi
   done
   if [ $i -eq $[$THREADLIMIT+1] ];then
      #echo "no free threads" >> $DBG
      echo 0
      #exit
   else
      echo $i
   fi
}

updateIPC()
{
   COMPLETE=$(cat $IPC)        #read IPC
   COMPLETE=$[$COMPLETE+1]     #increment IPC
   echo $COMPLETE > $IPC       #write back to IPC
}


worker()
{
   WORKERID=$1
   THREADID=$2
   #echo "new worker WORKERID:$WORKERID THREADID:$THREADID" >> $DBG

   #accessing common terminal requires critical blocking section
   (flock -x -w 10 201
      trackthread $WORKERID $THREADID setactive
   )201>/tmp/$ME.lock

   let "RND = $RANDOM % $MAXTHREADDUR +1"

   for s in $(seq 1 $RND)               #simulate random lifespan
   do
      sleep 1;
      (flock -x -w 10 201
         trackthread $WORKERID $THREADID update $s
      )201>/tmp/$ME.lock
   done

   (flock -x -w 10 201
      trackthread $WORKERID $THREADID setfree
   )201>/tmp/$ME.lock

   (flock -x -w 10 201
      updateIPC
   )201>/tmp/$ME.lock
}

threadcount()
{
   TC=$(ls /tmp/$ME.$F1* 2> /dev/null | wc -l)
   #echo threadcount is $TC >> $DBG
   THREADCOUNT=$TC
   echo $TC
}

status()
{
   #summary status line
   COMPLETE=$(cat $IPC)
   plot 1 $[$THREADLIMIT+2] "WORKERS $(threadcount)/$THREADLIMIT  SPAWNED $SPAWNED/$SPAWN  COMPLETE $COMPLETE/$SPAWN SF=$SPEEDFACTOR TIMING=$TPS"
   echo -en '\033[K'                   #clear to end of line
}

function main()
{
   while [ $SPAWNED -lt $SPAWN ]
   do
      while [ $(threadcount) -lt $THREADLIMIT ] && [ $SPAWNED -lt $SPAWN ]
      do
         WID=$(getfreeworkerid)
         worker $WID $SPAWNED &
         touch /tmp/$ME.$F1$WID    #if this loops faster than file creation in the worker thread it steps on itself, thread tracking is best in main loop
         SPAWNED=$[$SPAWNED+1]
         (flock -x -w 10 201
            status
         )201>/tmp/$ME.lock
         sleep $TPS
        if ((! $[$SPAWNED%100]));then
           #rethink thread timing every 100 threads
           threadspeed
        fi
      done
      sleep $TPS
   done

   while [ "$(threadcount)" -gt 0 ]
   do
      (flock -x -w 10 201
         status
      )201>/tmp/$ME.lock
      sleep 1;
   done

   status
}

clear
threadspeed
main
wait
status
echo

0

สคริปต์ของคุณควรมีลักษณะดังนี้:

prog1 &
prog2 &
.
.
progn &
wait
progn+1 &
progn+2 &
.
.

สมมติว่าระบบของคุณสามารถทำงานได้ครั้งละ n งาน ใช้ wait เพื่อรันงานเพียงครั้งละ n งานเท่านั้น


-1

ด้วยbashj ( https://sourceforge.net/projects/bashj/ ) คุณควรจะสามารถทำงานได้หลายกระบวนการ (วิธีที่คนอื่นแนะนำ) แต่ก็สามารถทำได้หลายเธรดใน JVM เดียวที่ควบคุมจากสคริปต์ของคุณ แต่แน่นอนว่าต้องใช้ Java JDK เธรดใช้ทรัพยากรน้อยกว่ากระบวนการ

นี่คือรหัสการทำงาน:

#!/usr/bin/bashj

#!java

public static int cnt=0;

private static void loop() {u.p("java says cnt= "+(cnt++));u.sleep(1.0);}

public static void startThread()
{(new Thread(() ->  {while (true) {loop();}})).start();}

#!bashj

j.startThread()

while [ j.cnt -lt 4 ]
do
  echo "bash views cnt=" j.cnt
  sleep 0.5
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.