0Pricing
Linux Command Line & Bash Scripting Mastery · บทเรียน

การจัดการเวิร์กโหลดด้วย GNU parallel

กระจายชุดข้อมูลเข้าขนาดใหญ่ไปยังแกนประมวลผลด้วย GNU parallel ช่องงาน และการจัดเรียงผลลัพธ์

การจัดการเวิร์กโหลดด้วย GNU parallel เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

GNU parallel คืออะไร และเหตุใดจึงควรใช้

GNU parallel เป็นเครื่องมือเชลล์ที่ช่วยให้คุณเรียกใช้งานแบบขนานบนเครื่องเดียวหรือหลายเครื่องได้ แทนที่จะประมวลผลรายการขนาดใหญ่ทีละรายการในลูป for parallel จะกระจายงานไปยังแกน CPU ที่พร้อมใช้งานทั้งหมดพร้อมกัน

  • ความเร็ว: งานที่ใช้เวลา 8 นาทีเมื่อทำตามลำดับ อาจเสร็จได้ในประมาณ 1 นาทีบนเครื่องที่มี 8 แกน
  • ความง่าย: รับอินพุตจากอินพุตมาตรฐาน ไฟล์ หรือรายการอาร์กิวเมนต์ได้ โดยไม่ต้องจัดการโพรเซสด้วยตนเอง
  • ความปลอดภัย: แยกเอาต์พุตจากงานต่าง ๆ ออกจากกัน ผลลัพธ์จะไม่สลับปะปนกัน

ติดตั้งด้วย sudo apt install parallel (Debian/Ubuntu) หรือ brew install parallel (macOS) จากนั้นตรวจสอบด้วย parallel --version

คำสั่ง parallel แรกของคุณ

รูปแบบที่ง่ายที่สุดของ parallel คืออ่านรายการจากอินพุตมาตรฐานและเรียกใช้คำสั่งสำหรับแต่ละรายการ ตัวแทน {} หมายถึงรายการอินพุตปัจจุบัน

ตัวอย่างด้านล่างบีบอัดไฟล์บันทึกห้าไฟล์พร้อมกันโดยใช้ gzip หากไม่มี parallel ไฟล์แต่ละไฟล์จะถูกบีบอัดทีละไฟล์ แต่เมื่อใช้แล้ว จะบีบอัดไฟล์ได้พร้อมกันสูงสุด N ไฟล์ (โดย N = จำนวนแกน CPU)

#!/usr/bin/env bash
# Create sample files first
for i in 1 2 3 4 5; do
  dd if=/dev/urandom bs=1M count=2 of="log_${i}.txt" 2>/dev/null
done

# Compress all of them in parallel
ls log_*.txt | parallel gzip {}

echo "Done. Compressed files:"
ls log_*.txt.gz

ควบคุมช่องงานด้วย -j

โดยค่าเริ่มต้น parallel จะเรียกใช้งานหนึ่งงานต่อแกน CPU หนึ่งแกน คุณสามารถกำหนดค่าใหม่ได้ด้วยแฟล็ก -j (หรือ --jobs)

  • -j 4 — เรียกใช้งาน 4 งานพอดีพร้อมกัน
  • -j 0 — เรียกใช้งานให้มากเท่าจำนวนอินพุต (ควรใช้อย่างระมัดระวัง!)
  • -j 200% — เรียกใช้งานเป็นสองเท่าของจำนวนแกน CPU (มีประโยชน์กับงานที่ใช้ I/O เป็นหลัก)
  • -j 50% — ใช้แกน CPU ที่พร้อมใช้งานเพียงครึ่งหนึ่ง

สำหรับงานที่ใช้ CPU เป็นหลัก -j $(nproc) มักเป็นค่าที่เหมาะสมที่สุด สำหรับงานเครือข่ายหรือดิสก์ คุณสามารถใช้จำนวนงานเกินจำนวนแกนได้อย่างปลอดภัย เนื่องจากงานใช้เวลาส่วนใหญ่รอ

#!/usr/bin/env bash
# Show how many cores are available
echo "CPU cores: $(nproc)"

# Run 8 sleep jobs but limit to 3 at a time
# -j 3 means at most 3 jobs run simultaneously
seq 1 8 | parallel -j 3 'echo "Starting job {}"; sleep 1; echo "Done job {}"'

echo "All jobs finished."

การอ่านอินพุตจากไฟล์และอาร์กิวเมนต์

parallel ยืดหยุ่นในเรื่องแหล่งที่มาของรายการอินพุต คุณไม่จำเป็นต้องส่งข้อมูลผ่านอินพุตมาตรฐานด้วยไพป์เท่านั้น

  • จากไฟล์: parallel -a urls.txt wget {}
  • รายการอาร์กิวเมนต์ในคำสั่ง: parallel echo ::: apple banana cherry
  • จากแหล่งอาร์กิวเมนต์หลายแหล่ง (ผลคูณคาร์ทีเซียน): parallel echo {1}-{2} ::: a b c ::: 1 2 — สร้างผลลัพธ์เป็น a-1, a-2, b-1, b-2, c-1, c-2
  • จากอินพุตมาตรฐานโดยระบุอย่างชัดเจน: cat list.txt | parallel -j4 process {}

ตัวคั่น ::: บอกให้ parallel ใช้ค่าที่ตามมาเป็นแหล่งอาร์กิวเมนต์ แทนการอ่านจากอินพุตมาตรฐาน

#!/usr/bin/env bash
# Inline list with :::
parallel echo 'Hello from {}' ::: Alice Bob Carol Dave

echo '---'

# Cartesian product: combine two lists
# Generates: dev-v1, dev-v2, prod-v1, prod-v2
parallel echo 'Deploy {1} to env {2}' ::: v1 v2 ::: dev prod

ตัวแทน: จัดการโทเค็นอินพุต

parallel มีการแทนที่ด้วยตัวแทนหลายรูปแบบ ซึ่งช่วยให้คุณดึงส่วนต่าง ๆ ของสตริงอินพุตได้โดยอัตโนมัติ มีประโยชน์อย่างยิ่งเมื่ออินพุตเป็นเส้นทางไฟล์

  • {} — รายการอินพุตทั้งหมด
  • {.} — อินพุตที่ไม่มีนามสกุลไฟล์ (report.csv → report)
  • {/} — เฉพาะชื่อพื้นฐาน (ตัดเส้นทางไดเรกทอรีออก)
  • {//} — เฉพาะเส้นทางไดเรกทอรี
  • {/.} — ชื่อพื้นฐานที่ไม่มีนามสกุล

สิ่งเหล่านี้ช่วยไม่ให้ต้องเรียกใช้ basename / dirname ภายในคำสั่งของงาน ทำให้ไปป์ไลน์สะอาดและทำงานเร็วขึ้น

#!/usr/bin/env bash
# Demonstrate placeholder substitutions
parallel --dry-run 'convert {} -resize 800x600 {.}_thumb.jpg' \
  ::: /photos/vacation/beach.png /photos/work/team.png

# {.}  strips extension: /photos/vacation/beach
# Result command shown (--dry-run does NOT execute):
#  convert /photos/vacation/beach.png -resize 800x600 /photos/vacation/beach_thumb.jpg
#  convert /photos/work/team.png      -resize 800x600 /photos/work/team_thumb.jpg
echo 'No files were changed (dry run)'

จัดลำดับเอาต์พุตด้วย --keep-order

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

แฟล็กสองตัวใช้ควบคุมลำดับเอาต์พุต:

  • --keep-order (-k) — แสดงเอาต์พุตของแต่ละงานตามลำดับเดียวกับอินพุต แม้งานที่อยู่หลังจะเสร็จก่อน เอาต์พุตจะถูกเก็บไว้ในบัฟเฟอร์จนกว่างานก่อนหน้าจะเสร็จ
  • --line-buffer — ทางสายกลาง: แสดงบรรทัดที่เสร็จสมบูรณ์ทันทีที่เข้ามาโดยไม่ต้องรอให้งานเสร็จ แต่จะไม่สลับปะปนบรรทัดที่เขียนไม่เสร็จ

ใช้ -k เมื่อโปรแกรมที่รับข้อมูลในขั้นถัดไปต้องการผลลัพธ์ตามลำดับอินพุต (เช่น การสร้างรายงานที่เรียงลำดับแล้ว) ไม่ต้องใช้เมื่อไม่สำคัญว่าลำดับจะเป็นอย่างไร และคุณต้องการเห็นผลลัพธ์โดยเร็วที่สุด

#!/usr/bin/env bash
# Without -k: output order is unpredictable
echo '--- Without --keep-order ---'
seq 5 1 1 | parallel 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'

echo

# With -k: output always appears as 5, 4, 3, 2, 1
echo '--- With --keep-order (-k) ---'
seq 5 1 1 | parallel -k 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'

จัดกลุ่มเอาต์พุตเพื่อหลีกเลี่ยงการสอดแทรกกัน

แม้เอาต์พุตจะเรียงตามลำดับแล้ว หากงานหนึ่งพิมพ์หลายบรรทัด บรรทัดเหล่านั้นก็อาจสอดแทรกกับบรรทัดจากงานอื่นที่กำลังทำงานอยู่พร้อมกันได้ parallel จะแก้ปัญหานี้โดยอัตโนมัติด้วยการบัฟเฟอร์ stdout และ stderr ทั้งหมดของแต่ละงาน จากนั้นจึงพิมพ์ออกมาเป็นบล็อกเดียวแบบอะตอมิกเมื่องานนั้นเสร็จสิ้น

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

  • ค่าเริ่มต้น: จัดกลุ่มเอาต์พุตแยกตามงาน — ปลอดภัยสำหรับการแยกวิเคราะห์
  • --ungroup: สตรีมเอาต์พุตแบบสด — เหมาะสำหรับการตรวจสอบแบบโต้ตอบ
  • --line-buffer: ทางสายกลาง — บรรทัดจะไม่ถูกแบ่ง แต่แต่ละงานอาจสอดแทรกกันตรงรอยต่อระหว่างบรรทัด

ส่งอาร์กิวเมนต์ภายในฟังก์ชันเชลล์

บางครั้งงานที่คุณต้องการทำแบบขนานมีมากกว่าคำสั่งเดียว แต่เป็นฟังก์ชันเชลล์ที่มีหลายขั้นตอน คุณสามารถส่งฟังก์ชันให้ parallel ได้โดยใช้ export -f ร่วมกับ env_parallel หรือเรียกใช้ bash -c โดยตรง

แนวทางแบบพกพาที่ปลอดภัยที่สุดสำหรับงานซับซ้อนคือรูปแบบ bash -c '...' ตัวแทน {} จะถูกส่งเป็น $1 เมื่อคุณลงท้ายด้วย _ {}

#!/usr/bin/env bash
# Define a multi-step processing function
process_item() {
  local item="$1"
  echo "[START] $item"
  # Simulate two steps
  sleep 0.2
  local result=$(echo "$item" | tr '[:lower:]' '[:upper:]')
  echo "[END]   $item -> $result"
}

export -f process_item

# Run the function in parallel for each input
echo 'alpha beta gamma delta epsilon' | tr ' ' '\n' \
  | parallel -j 3 process_item {}

ควบคุมความถี่และลองใหม่ด้วย --delay และ --retries

เมื่อเรียกใช้บริการภายนอก (API เซิร์ฟเวอร์ระยะไกล ฐานข้อมูล) แบบขนาน คุณมักต้องจำกัดอัตราการเรียกใช้และรองรับความผิดพลาด

  • --delay N — รอ N วินาทีระหว่างการเริ่มงานใหม่แต่ละงาน (อนุญาตให้ใช้ค่าเศษส่วน เช่น 0.5) ป้องกันไม่ให้บริการรับคำขอจำนวนมากเกินไป
  • --retries N — หากงานจบลงด้วยสถานะที่ไม่ใช่ศูนย์ ให้ลองใหม่ได้สูงสุด N ครั้งก่อนยอมแพ้ การลองใหม่แต่ละครั้งจะนับเป็นช่องงานใหม่
  • --timeout N — ยุติงานหากทำงานนานเกิน N วินาที เมื่อใช้ร่วมกับ --retries จะช่วยจัดการงานที่ค้างได้อย่างเหมาะสม

ตัวอย่าง: ดาวน์โหลด URL 50 รายการ โดยมีการเชื่อมต่อพร้อมกันไม่เกิน 4 รายการ หน่วงเวลา 0.5 วินาทีระหว่างการเริ่มต้นแต่ละครั้ง และลองใหม่ 3 ครั้งเมื่อเกิดข้อผิดพลาด

#!/usr/bin/env bash
# Simulate downloading URLs with throttling and retries
# (using echo instead of curl so this is self-contained)

download_url() {
  local url="$1"
  # Randomly fail ~30% of the time to demo --retries
  if (( RANDOM % 10 < 3 )); then
    echo "FAIL: $url" >&2
    return 1
  fi
  echo "OK:   $url downloaded"
}

export -f download_url

printf 'https://example.com/file%d\n' $(seq 1 10) \
  | parallel -j 4 --delay 0.2 --retries 3 download_url {}

echo 'All downloads attempted.'

กระจายงานไปยังโฮสต์ระยะไกลด้วย --sshloginfile

parallel สามารถกระจายงานไปยังเครื่องระยะไกลผ่าน SSH ได้อย่างโปร่งใส ทำให้เป็นเครื่องมือประมวลผลแบบคลัสเตอร์ขนาดย่อมโดยไม่ต้องใช้ซอฟต์แวร์คลัสเตอร์เฉพาะ

  • --sshlogin user@host — เรียกใช้งานบนโฮสต์ระยะไกลที่ระบุ
  • --sshloginfile machines.txt — อ่านรายชื่อโฮสต์จากไฟล์ (หนึ่งรายการต่อบรรทัด) ใช้ : เป็นรายการพิเศษเพื่อใช้เครื่องภายในเครื่องนี้ด้วย
  • --transfer — คัดลอกไฟล์อินพุตไปยังโฮสต์ระยะไกลก่อนประมวลผล
  • --return {} — คัดลอกไฟล์ผลลัพธ์กลับมาหลังงานเสร็จสิ้น
  • --cleanup — ลบไฟล์ที่ถ่ายโอนไปจากโฮสต์ระยะไกลหลังดึงไฟล์กลับมาแล้ว

โฮสต์ระยะไกลต้องติดตั้ง parallel และกำหนดค่าการยืนยันตัวตนด้วยคีย์ SSH ไว้แล้ว (ไม่ต้องมีการถามรหัสผ่าน)

รายงานความคืบหน้าและการบันทึก

สำหรับงานที่ทำงานเป็นเวลานาน การตรวจสอบความคืบหน้าและวิเคราะห์สาเหตุของความล้มเหลวภายหลังเป็นสิ่งสำคัญอย่างยิ่ง

  • --progress — พิมพ์บรรทัดสรุปแบบสดที่แสดงจำนวนงานที่กำลังทำงาน เสร็จแล้ว และเหลืออยู่
  • --eta — ประมาณเวลาที่จะเสร็จโดยอิงจากระยะเวลาเฉลี่ยของงานจนถึงขณะนั้น
  • --joblog results.log — เขียนไฟล์บันทึกที่คั่นด้วยแท็บ โดยมีหนึ่งแถวต่องานที่เสร็จแล้ว รวมถึงรหัสการออก ระยะเวลาทำงาน และคำสั่งที่เรียกใช้ ซึ่งมีประโยชน์อย่างยิ่งสำหรับการตรวจสอบข้อผิดพลาด
  • --resume --joblog results.log — ข้ามงานที่มีอยู่แล้วในไฟล์บันทึก (และมีรหัสการออกเป็น 0) หากการทำงานเป็นชุดถูกขัดจังหวะ คุณสามารถทำต่อได้โดยไม่ต้องทำงานที่สำเร็จแล้วซ้ำ

การใช้ --joblog + --resume ร่วมกันเป็นหนึ่งในความสามารถที่ทรงพลังที่สุดของ GNU parallel สำหรับไปป์ไลน์การทำงานจริงที่มีความทนทาน

#!/usr/bin/env bash
LOGFILE="/tmp/parallel_demo_$$.log"

# Run jobs and record results to a log
seq 1 12 | parallel \
  --jobs 4 \
  --progress \
  --joblog "$LOGFILE" \
  'sleep 0.1; echo "Processed item {}"'

echo
echo '=== Job Log (first 5 entries) ==='
head -6 "$LOGFILE"

# Show only failed jobs (exit value != 0)
echo '=== Failed jobs ==='
awk 'NR>1 && $7 != 0 { print $0 }' "$LOGFILE" || echo '(none)'

rm -f "$LOGFILE"

แบบทดสอบความเข้าใจ: แฟล็กช่องงาน

ทดสอบความเข้าใจของคุณเกี่ยวกับวิธีที่ parallel ควบคุมการทำงานพร้อมกัน

สรุปบทเรียน: จัดการงานด้วย GNU parallel

คุณได้เรียนรู้ชุดเครื่องมือหลักสำหรับกระจายชุดอินพุตขนาดใหญ่ไปยังแกน CPU ด้วย GNU parallel แล้ว สิ่งสำคัญที่ควรจดจำมีดังนี้:

  • การใช้งานพื้นฐาน: ส่งรายการเข้าไปใน parallel command {} — {} จะถูกแทนที่ด้วยรายการอินพุตแต่ละรายการ
  • ช่องงาน (-j): ควบคุมการทำงานพร้อมกันได้อย่างแม่นยำ — ใช้จำนวนแกนสำหรับงานที่จำกัดด้วย CPU และใช้เปอร์เซ็นต์ที่สูงขึ้นสำหรับงานที่จำกัดด้วยการรับส่งข้อมูล
  • ตัวแทน ({.}, {/}, {//}, {/.}) ช่วยแยกส่วนประกอบของเส้นทางได้อย่างสะอาดโดยไม่ต้องใช้คำสั่งเพิ่มเติม
  • การควบคุมเอาต์พุต: -k รักษาลำดับของอินพุต การจัดกลุ่มเป็นค่าเริ่มต้นช่วยป้องกันการสอดแทรกของบรรทัด และ --ungroup ให้การสตรีมแบบสด
  • ความทนทาน: --retries, --timeout และ --delay ทำให้ไปป์ไลน์แบบขนานรับมือกับงานที่ไม่เสถียรและข้อจำกัดอัตราการเรียกใช้ได้ดี
  • ความสามารถในการตรวจสอบ: --joblog บันทึกผลลัพธ์ของทุกงาน และ --resume ช่วยให้ทำต่อจากจุดที่หยุดไว้ได้หลังเกิดการขัดจังหวะ
  • การขยายไปยังเครื่องอื่น: --sshloginfile กระจายงานไปยังเครื่องระยะไกลผ่าน SSH โดยแทบไม่เพิ่มภาระของคลัสเตอร์

เมื่อเชี่ยวชาญตัวเลือกเหล่านี้แล้ว parallel จะกลายเป็นเครื่องมือจัดการงานระดับใช้งานจริงที่มีอยู่ในเชลล์ของคุณโดยตรง

คำถามที่พบบ่อย

บทเรียน “การจัดการเวิร์กโหลดด้วย GNU parallel” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการเวิร์กโหลดด้วย GNU parallel” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการเวิร์กโหลดด้วย GNU parallel”

กระจายชุดข้อมูลเข้าขนาดใหญ่ไปยังแกนประมวลผลด้วย GNU parallel ช่องงาน และการจัดเรียงผลลัพธ์ คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การจัดการเวิร์กโหลดด้วย GNU parallel” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม

ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การวิเคราะห์ประสิทธิภาพสคริปต์และการหลีกเลี่ยง subshell ที่ไม่จำเป็น
  2. การทำงานแบบขนานด้วย xargs -P และงานเบื้องหลัง
  3. การจัดการเวิร์กโหลดด้วย GNU parallel
  4. ไปป์ไลน์แบบสตรีมและไปป์ที่ตั้งชื่อเพื่อเพิ่มอัตรารับส่งข้อมูล
← กลับไปที่ Linux Command Line & Bash Scripting Mastery