การจัดการเวิร์กโหลดด้วย GNU parallel
กระจายชุดข้อมูลเข้าขนาดใหญ่ไปยังแกนประมวลผลด้วย GNU parallel ช่องงาน และการจัดเรียงผลลัพธ์
การจัดการเวิร์กโหลดด้วย GNU parallel เป็นบทเรียน DevOps Bootcamp ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน DevOps Bootcamp และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส DevOps Bootcamp มีบทเรียนทั้งหมด 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) และปลดล็อคส่วนที่เหลือของคอร์ส DevOps Bootcamp ให้อัปเกรดเป็น CoddyKit PRO คอร์ส DevOps Bootcamp มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจัดการเวิร์กโหลดด้วย GNU parallel”
กระจายชุดข้อมูลเข้าขนาดใหญ่ไปยังแกนประมวลผลด้วย GNU parallel ช่องงาน และการจัดเรียงผลลัพธ์ คุณปฏิบัติ DevOps Bootcamp ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน DevOps Bootcamp หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน DevOps Bootcamp บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การจัดการเวิร์กโหลดด้วย GNU parallel” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน DevOps Bootcamp นี้ได้ไหม
ได้ บทเรียน DevOps Bootcamp ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การวิเคราะห์ประสิทธิภาพสคริปต์และการหลีกเลี่ยง subshell ที่ไม่จำเป็น
- การทำงานแบบขนานด้วย xargs -P และงานเบื้องหลัง
- การจัดการเวิร์กโหลดด้วย GNU parallel
- ไปป์ไลน์แบบสตรีมและไปป์ที่ตั้งชื่อเพื่อเพิ่มอัตรารับส่งข้อมูล