0Pricing
Linux Command Line & Bash Scripting Mastery · درس

تنسيق أحمال العمل باستخدام GNU parallel

وزّع مجموعات الإدخال الكبيرة على أنوية المعالج باستخدام GNU parallel وفتحات المهام وترتيب النتائج

تنسيق أحمال العمل باستخدام GNU parallel درس مجاني في Linux Command Line & Bash Scripting Mastery على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Linux Command Line & Bash Scripting Mastery، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Linux Command Line & Bash Scripting Mastery 4 دروس في المجموع.

ما هي GNU parallel ولماذا تُستخدم؟

إن GNU parallel أداة للصدفة تتيح لكم تشغيل المهام بالتوازي على جهاز واحد أو عدة أجهزة. فبدلًا من معالجة قائمة كبيرة من العناصر واحدًا تلو الآخر في حلقة for، توزّع parallel العمل على جميع أنوية المعالج المتاحة في الوقت نفسه.

  • السرعة: يمكن لمهمة تستغرق 8 دقائق تسلسليًا أن تنتهي في نحو دقيقة واحدة على جهاز ذي 8 أنوية.
  • البساطة: تقبل المدخلات من stdin أو الملفات أو قوائم الوسائط، من دون الحاجة إلى إدارة العمليات يدويًا.
  • الأمان: تبقي مخرجات المهام المختلفة منفصلة؛ فلا تختلط النتائج أبدًا.

ثبّتوها باستخدام sudo apt install parallel (Debian/Ubuntu) أو brew install parallel (macOS). وتحققوا من التثبيت باستخدام parallel --version.

أول أمر لكم باستخدام parallel

يقرأ الشكل الأبسط من parallel العناصر من stdin ويشغّل أمرًا لكل عنصر. ويمثل العنصر النائب {} عنصر الإدخال الحالي.

يضغط المثال أدناه خمسة ملفات سجل بالتزامن باستخدام gzip. من دون parallel، سيُضغط كل ملف بعد الآخر. أما معها، فيمكن ضغط ما يصل إلى N من الملفات (حيث إن N = عدد أنوية المعالج) في الوقت نفسه.

#!/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 افتراضيًا مهمة واحدة لكل نواة معالج. ويمكنكم تجاوز ذلك باستخدام الخيار -j (أو --jobs).

  • -j 4 — تشغيل 4 مهام بالضبط في الوقت نفسه
  • -j 0 — تشغيل عدد من المهام يساوي عدد المدخلات (استخدموه بحذر!)
  • -j 200% — تشغيل عدد من المهام يساوي ضعف عدد أنوية المعالج (مفيد للأعمال المقيّدة بعمليات الإدخال والإخراج)
  • -j 50% — استخدام نصف الأنوية المتاحة فقط

للمهام المقيّدة بالمعالج، غالبًا ما يكون -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 بالمرونة في مصدر قائمة المدخلات. فلستم مقيّدين بالتمرير عبر stdin.

  • من ملف: 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
  • من stdin صراحةً: cat list.txt | parallel -j4 process {}

يخبر الفاصل ::: أداة parallel باستخدام القيم التالية كمصدر للوسائط بدلًا من القراءة من stdin.

#!/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: حلّ وسط — لا تُقسّم الأسطر أبدًا، لكن يمكن أن تتداخل المهام عند حدود الأسطر.

تمرير الوسائط داخل دوال Shell

أحيانًا تكون المهمة التي تريدون تشغيلها بالتوازي أكثر من أمر واحد — بل تكون دالة Shell متعددة الخطوات. يمكنكم تمرير دالة إلى 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، يتعامل هذا الخيار بسلاسة مع المهام المعلّقة.

مثال: تنزيل 50 عنوان URL بحد أقصى 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

لقد تعلّمتم الأدوات الأساسية لتوزيع مجموعات الإدخال الكبيرة على أنوية وحدة المعالجة المركزية باستخدام GNU parallel. إليكم أهم النقاط:

  • الاستخدام الأساسي: مرّروا قائمة إلى parallel command {} — حيث يُستبدل {} بكل عنصر من عناصر الإدخال.
  • فتحات المهام (-j): تتحكّم بدقة في التزامن — استخدموا عدد الأنوية للأعمال المقيّدة بوحدة المعالجة المركزية، ونسبًا مئوية أعلى للأعمال المقيّدة بعمليات الإدخال والإخراج.
  • العناصر النائبة ({.} و{/} و{//} و{/.}) تستخرج مكوّنات المسار بسهولة ومن دون أوامر إضافية.
  • التحكّم في المخرجات: يحافظ -k على ترتيب الإدخال؛ ويمنع التجميع الافتراضي تداخل الأسطر؛ بينما يوفّر --ungroup بثًا مباشرًا.
  • المرونة: تجعل الخيارات --retries و--timeout و--delay مسارات المعالجة المتوازية متينة في مواجهة المهام غير المستقرة وحدود معدّل الطلبات.
  • قابلية التدقيق: يسجّل --joblog نتيجة كل مهمة؛ ويتيح لكم --resume المتابعة من حيث توقفتم بعد انقطاع التشغيل.
  • التوسّع الأفقي: يوزّع --sshloginfile المهام على أجهزة بعيدة عبر SSH من دون أي عبء إضافي لإدارة العناقيد.

يحوّل إتقان هذه الخيارات parallel إلى منسّق لأحمال العمل بمستوى الإنتاج، مدمج مباشرةً في Shell.

الأسئلة الشائعة

هل درس «تنسيق أحمال العمل باستخدام GNU parallel» مجاني؟

نعم — نص درس «تنسيق أحمال العمل باستخدام GNU parallel» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تحليل أداء السكربتات وتجنّب subshells غير الضرورية
  2. التوازي باستخدام xargs -P والمهام الخلفية
  3. تنسيق أحمال العمل باستخدام GNU parallel
  4. خطوط الأنابيب المتدفقة والأنابيب المسماة لزيادة الإنتاجية
← العودة إلى Linux Command Line & Bash Scripting Mastery