كيف يمكنني فرض الحد الأقصى لعدد الأطفال المتشعبين؟

StackOverflow https://stackoverflow.com/questions/336250

سؤال

يحرر:لقد قمت بوضع علامة على هذا C على أمل الحصول على مزيد من الاستجابة.إنها النظرية التي أهتم بها أكثر من تطبيق لغة معينة.لذا، إذا كنت من مبرمجي لغة C، فيرجى التعامل مع PHP التالي كرمز زائف ولا تتردد في الرد بإجابة مكتوبة بلغة C.

أحاول تسريع البرنامج النصي PHP CLI من خلال جعله ينفذ مهامه بالتوازي بدلاً من التسلسل.المهام مستقلة تمامًا عن بعضها البعض، لذلك لا يهم الترتيب الذي تبدأ به/تنتهي به.

إليك النص الأصلي (لاحظ أن جميع هذه الأمثلة قد تم تجريدها من أجل الوضوح):

<?php

$items = range(0, 100);

function do_stuff_with($item) { echo "$item\n"; }

foreach ($items as $item) {
    do_stuff_with($item);
}

لقد تمكنت من جعله يعمل على $items بالتوازي مع pcntl_fork() كما هو مبين أدناه:

<?php

ini_set('max_execution_time', 0); 
ini_set('max_input_time', 0); 
set_time_limit(0);

$items = range(0, 100);

function do_stuff_with($item) { echo "$item\n"; }

$pids = array();
foreach ($items as $item) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("couldn't fork()");
    } elseif ($pid > 0) {
        // parent
        $pids[] = $pid;
    } else {
        // child
        do_stuff_with($item);
        exit(0);
    }   
}

foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
}

الآن أريد تمديد هذا بحيث يكون هناك، على سبيل المثال، 10 أطفال كحد أقصى نشطين في وقت واحد.ما هي أفضل طريقة للتعامل مع هذا؟لقد جربت بعض الأشياء ولكن لم يحالفني الحظ كثيرًا.

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

المحلول

وليس هناك syscall للحصول على قائمة من PIDS الطفل، ولكن ps تستطيع ان تفعل ذلك بالنسبة لك.

والتبديل --ppid سوف قائمة جميع الأطفال بالنسبة لك معالجة لذلك أنت بحاجة فقط لحساب عدد خطوط أنتج من قبل ps.

وبدلا من ذلك يمكنك الحفاظ على مكافحة الخاصة بك أنك لن زيادة على fork() والتناقص في إشارة SIGCHLD، على افتراض ppid يبقى دون تغيير لfork'ed معالجتها.

نصائح أخرى

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

الشوكة هي عملية مكلفة.من مظهره، ما تريده حقًا هو متعددخيوط, ، ليست متعددةيعالج.والفرق هو أن سلاسل العمليات أخف وزنًا بكثير من العمليات، نظرًا لأن سلاسل العمليات تشترك في مساحة عنوان افتراضية ولكن العمليات لها مساحات عناوين افتراضية منفصلة.

أنا لست مطور PHP، ولكن البحث السريع على Google يكشف أن PHP لا يدعم تعدد مؤشرات الترابط محليًا، ولكن هناك مكتبات للقيام بهذه المهمة.

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

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

إذا كنت مقيدًا بالذاكرة، فلن يساعدك تعدد العمليات.

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

أحد الخيارات هو استخدام تجمعات سلاسل الرسائل - حيث تقوم بإنشاء مجموعة كاملة من سلاسل الرسائل، ثم لكل عنصر تتم معالجته، ترى ما إذا كان هناك مؤشر ترابط مجاني في التجمع.إذا كان هناك، لديك هذا الخيط الذي يقوم بالعمل، وتنتقل إلى العنصر التالي.وإلا، عليك الانتظار حتى يصبح الموضوع متاحًا.يعد اختيار حجم تجمع مؤشرات الترابط أمرًا مهمًا - فهو كبير جدًا، وأنت تهدر الوقت في إجراء تبديلات غير ضرورية للسياق.عدد قليل جدًا، وتنتظر المواضيع كثيرًا.

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

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

$my_process_index = 0;
$pids = array();

// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
  $pid = pcntl_fork();
  if($pid == -1)
  {
    die("couldn't fork()");
  }
  elseif($pid > 0)
  {
    // parent
    $my_process_index++;
    $pids[] = $pid
  }
  else
  {
    // child
    break;
  }
}

// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
  do_stuff_with($items[$i]);
}

if($my_process_index != 0)
{
  exit(0);
}

ورجل 2 setrlimit

وهذا سيكون لكل مستخدم الذي <م> قد يكون ما تريد على أي حال.

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