2010-10-22 4 views
2

Объяснение: Часть приложение, которое я создаю требует проверки тысяч записей и действующих на них в своевременно образом. Поэтому для каждой записи я хочу разблокировать новый процесс. Тем не менее, мне нужно соединение с БД, чтобы выполнить некоторую проверку этой записи. Насколько я понимаю, он наследует соединение БД. Поэтому последующие вилки имеют ошибки БД.pcntl_fork, а затем pcntl_exec или pcntl_exec, а затем pcntl_fork

Я думал, что могу pcntl_exec ('php /path/script.php'); а затем pcntl_fork, чтобы вызывающий процесс не задерживался.

Или я могу pcntl_fork, а затем pcntl_exec в дочернем процессе. Или, может быть, я должен использовать exec() вместо pcntl_exec().

Мой вопрос: Есть ли недостатки или преимущества для любого заказа?

Примечание: Может быть, я себе этот вопрос, как я думал, что вызывающий процесс PHP будет ждать pcntl_exec вернуться. Но это не то, что говорится в документах:

Возвращает FALSE при ошибке и не возвращается к успеху.

Как функция может возвращать значение иногда и в другое время? Это звучит как плохо написанные документы.

fahadsadah в комментарии состояние:

После того, как выполняется процесс завершается, управление возвращается к процессу веб-сервера.

Если это так, то мне нужно использовать вилку.

Edit: код запутанный - включая меня;)

<?php 

class Process 
{ 

    public function __construct($arg = false) 
    { 
     if ($arg == "child") 
     { 
      $this->act(); 
     } 
     else 
     { 
      $this->run(); 
     } 
    } 

    public function run() 
    { 
     echo "parent before fork:", getmypid(), PHP_EOL; 
     $pid = @ pcntl_fork(); 
     echo $pid, PHP_EOL; 

     if ($pid == -1) 
     { 
      throw new Exception(self::COULD_NOT_FORK); 
     } 
     if ($pid) 
     { 
     // parent 
      echo "parent after fork:", getmypid(), PHP_EOL; 
     } 
     elseif ($pid == 0) 
     { 
     // child 
      echo "child after fork:", getmypid(), PHP_EOL; 
      //echo exec('php Process.php child'); 
      echo pcntl_exec('/usr/bin/php', array('Process.php', 'child')); 
     } 
     return 0; 
    } 

    private function act() 
    { 
     sleep(1); 
     echo "forked child new process:", getmypid(), PHP_EOL; 
     return 0; 
    } 
} 

$proc = new Process($argv[1]); 

Если вы раскомментировать ехес и комментировать pcntl_exec, вы увидите, что pcntl_exec заменяет процесс. Я предполагаю, что это экономит ресурсы.

+0

* (учебник) * [Control Process] (http://www.tuxradar.com/practicalphp/16/1/ 0 «Практический PHP-файл TuxRadar»). В качестве побочного элемента вам нужно использовать расширение 'pcntl' или что-то вроде [Gearman] (http://de2.php.net/manual/en/book.gearman.php) лучше подходить? – Gordon

+0

Хорошая статья. Однако не ответил на все вопросы. Я знаю о Гирмене. Я не думаю, что хочу представить новую зависимость, но, возможно, это путь в будущее. Мне нужен мой процесс, чтобы получить доступ ко всему, что делает родитель. Он должен иметь доступ к БД и всем тем же классам - скажем: Zend lazy loading. Я не знаю, сможет ли Гирман справиться с этим. –

+0

Я предложил бы голосование людям, которые помогли вам. :/ – Madbreaks

ответ

0

Это не имеет смысла. После того, как вы выполните exec(), у вас запущен другой код, поэтому не может fork(). Не возвращается на успех.

+0

Пожалуйста, объясните, почему это не имеет смысла. –

+0

Я думал, что уже сделал это. Что вы не поняли? – EJP

+0

Вы наверняка можете разветвить. Вы открываете недавно выполненный процесс. Возможно, это то, что я пытаюсь сделать. Но это может быть плохая идея. –

1

Это действительно смущает - вы пытаетесь применить очень сложные методы, но вы применяете их совершенно неправильно.

fork создает новую текущую копию текущего процесса. Exec запускает новый процесс. Вы бы не использовали их для запуска одного процесса.

Но прежде чем я получу разъяснение, как правильно использовать fork и exec, я должен указать, что они не являются подходящими инструментами для решения этой проблемы.

Следует избегать периодической обработки, где это возможно.Обычно данные поступают с конечной скоростью (хотя скорость может быть стохастической) - обычно правильный подход, чтобы избежать пакетной обработки, заключается в том, чтобы обрабатывать запросы синхронно или через очередность. В тех случаях, когда периодическая обработка неизбежна, обработка распараллеливанием и/или конвейерной обработкой обычно повышает пропускную способность. Хотя существует множество сложных методов для достижения этой цели (например, уменьшение карты), просто обход данных обычно является достаточным. В то время как ваша основная идея сводится к шардингу на отдельные куски, это:

1) будет менее эффективным, чем иметь дело с небольшими партиями

2) делает его очень трудно ограничить потребление ресурсов системы (что, если вы икру 500 и ваша СУБД поддерживает только 200 параллельных соединений?)

Предполагая, что вы не можете обрабатывать синхронно и запускать очередь с несколькими подписчиками, это не практично, я бы предложил просто разбивать данные на (ограниченный количество) меньших партий и процессов нереста для борьбы с ними. Обратите внимание, что popen(), proc_open() и pcntl_fork() не блокируются на время выполнения порожденного процесса. (подсказка - используйте modulus operator)

Если вы хотите запустить обработку из HTTP-запроса (или иметь другую причину для их запуска в отдельных группах сеансов), тогда у вас есть google for 'PHP long running processes setsid).

+0

Это сценарий командной строки. Это не касается запросов. Пользователь изменяет БД, что может вызвать определенные действия - в зависимости от конфигурации системы. Таким образом, сохраняется журнал изменений, которые могут вызвать запуск и действие. Задача cron проверяет этот журнал на действия, которые необходимо выполнить. Таким образом, он не имеет ничего общего с HTTP-запросами. –

+0

Да - вы пытаетесь решить проблему, используя скрипт командной строки, но действительно ли вы вводили данные вручную? Как он туда попал? Почему вы не справлялись с этим, когда «пользователь меняет базу данных» – symcbean

+0

Поскольку пользователь может настроить систему на реакцию после истечения срока. Например, «напомните всем сотрудникам, что встреча проходит через 15 минут», это всего лишь одно простое действие, которое система может/должна быть в состоянии сделать. –

0

Теперь, когда fork и exec определены, вилка не будет делать то, что вы хотите. Он скопирует ВСЕ текущую среду сценария в новое пространство, включая дескриптор файла указателей. Да, это правильно - дети имеют одни и те же файловые дескрипторы, что и родители.

Представьте себе хаос при использовании расширения MySQL, который поддерживает свой собственный файл дескрипторов ;-)

Смежные вопросы