سؤال

لتعظيم استخدام وحدة المعالجة المركزية (أركض الأشياء في Debian Lenny في EC2) لدي برنامج نصي بسيط لإطلاق وظائف بالتوازي:

#!/bin/bash

for i in apache-200901*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200902*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200903*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200904*.log; do echo "Processing $i ..."; do_something_important; done &
...

أنا راض تماما عن حل العمل هذا، ومع ذلك، لم أستطع معرفة كيفية كتابة مزيد من التعليمات البرمجية التي تم تنفيذها إلا بمجرد الانتهاء من جميع الحلقات.

هل هناك طريقة للسيطرة على هذا؟

هل كانت مفيدة؟

المحلول

هناك bash الأمر المدمج لذلك.

wait [n ...]
      Wait for each specified process and return its termination  sta‐
      tus.   Each  n  may be a process ID or a job specification; if a
      job spec is given, all processes  in  that  job’s  pipeline  are
      waited  for.  If n is not given, all currently active child pro‐
      cesses are waited for, and the return  status  is  zero.   If  n
      specifies  a  non-existent  process or job, the return status is
      127.  Otherwise, the return status is the  exit  status  of  the
      last process or job waited for.

نصائح أخرى

سيجعل استخدام GNU ParAllel النصي الخاص بك أقصر وربما أكثر كفاءة:

parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log

سيعمل ذلك على تشغيل وظيفة واحدة لكل وحدة المعالجة المركزية الأساسية وتستمر في القيام بذلك حتى تتم معالجة جميع الملفات.

سوف ينقسم الحل الخاص بك في الأساس الوظائف في مجموعات قبل التشغيل. هنا 32 وظيفة في 4 مجموعات:

Simple scheduling

تضع GNU متوازي بدلا من ذلك عملية جديدة عند انتهاء المرء - الحفاظ على وحدة المعالجة المركزية النشطة وبالتالي توفير الوقت:

GNU Parallel scheduling

لتعلم المزيد:

اضطررت للقيام بذلك مؤخرا وانتهى الأمر بالحل التالي:

while true; do
  wait -n || {
    code="$?"
    ([[ $code = "127" ]] && exit 0 || exit "$code")
    break
  }
done;

وإليك كيف يعمل:

wait -n يخرج بمجرد خروج أحد وظائف الخلفية (المحتملة). يقيم دائما إلى TRUE ويتماشى الحلقة حتى:

  1. رمز الخروج 127: خرجت وظيفة الخلفية الأخيرة بنجاح. في هذه الحالة، نتجاهل رمز الخروج والخروج من Sub-Shell برمز 0.
  2. فشل أي من مهمة الخلفية. نحن فقط الخروج من شل الفرعية مع هذا الرمز الخروج.

مع set -e, ، سيضمن هذا أن البرنامج النصي سينتهي مبكرا وتمرير رمز الخروج لأي وظيفة خلفية فاشلة.

هذا هو الحل الخام الخاص بي:

function run_task {
        cmd=$1
        output=$2
        concurency=$3
        if [ -f ${output}.done ]; then
                # experiment already run
                echo "Command already run: $cmd. Found output $output"
                return
        fi
        count=`jobs -p | wc -l`
        echo "New active task #$count:  $cmd > $output"
        $cmd > $output && touch $output.done &
        stop=$(($count >= $concurency))
        while [ $stop -eq 1 ]; do
                echo "Waiting for $count worker threads..."
                sleep 1
                count=`jobs -p | wc -l`
                stop=$(($count > $concurency))
        done
}

الفكرة هي استخدام "وظائف" لمعرفة عدد الأطفال النشطين في الخلفية والانتظار حتى يسقط الرقم هذا (مخارج طفل). بمجرد وجود طفل، يمكن بدء المهمة التالية.

كما ترون، يوجد أيضا منطق إضافي لتجنب تشغيل نفس التجارب / الأوامر عدة مرات. إنه يفعل المهمة بالنسبة لي .. ومع ذلك، يمكن تخطي هذا المنطق أو تحسينه (على سبيل المثال، تحقق من طابع الطابع الزمني لإنشاء الملفات، معلمات الإدخال، إلخ).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top