Как мне сохранить соединение MySQL в родительском процессе после pcntl_fork? - PullRequest
4 голосов
/ 20 апреля 2011

Как вы все знаете, когда вы разветвляетесь, ребенок получает копию всего, включая файловые и сетевые дескрипторы - man fork.

В PHP, когда вы используете pcntl_fork, все ваши соединения, созданные с помощью mysql_connect,скопировал, и это является некоторой проблемой - php docs и ТАК вопрос .Здравый смысл в этой ситуации гласит: закройте родительскую связь, создайте новую и дайте ребенку использовать старую.Но что, если указанные родительские потребности создают много детей за несколько секунд?В этом случае вы в конечном итоге создаете загрузок новых соединений - по одному на каждую связку вилок.

Что это означает в коде:

while (42) {

  $db = mysql_connect($host, $user, $pass);

  // do some stuff with $db
  // ...

  foreach ($jobs as $job) {
        if (($pid = pcntl_fork()) == -1) {
            continue;
        } else if ($pid) {
            continue;
        }
    fork_for_job($job);
  }

  mysql_close($db);
  wait_children();
  sleep(5);
}

function fork_for_job($job) {

  // do something. 
  // does not use the global $db 
  // ...

  exit(0);
}

Ну, яне хочу этого делать - слишком много подключений к базе данных.В идеале я хотел бы иметь возможность добиться поведения, подобного этому:

$db = mysql_connect($host, $user, $pass);

while (42) {

  // do some stuff with $db
  // ...

  foreach ($jobs as $job) {
        if (($pid = pcntl_fork()) == -1) {
            continue;
        } else if ($pid) {
            continue;
        }
    fork_for_job($job);
  }

  wait_children();
  sleep(5);
}

function fork_for_job($job) {

  // do something
  // does not use the global $db 
  // ...

  exit(0);
}

Как вы думаете, возможно ли это?

Некоторые другие вещи:

  • Это скрипт php-cli
  • Я пытался использовать mysql_pconnect в первом примере, но, насколько я могу судить, разницы нет - сервер mysql получает столько новых соединений.Может быть, это потому, что это cli и pconnect не работает, как это было в mod_php. Как заметил Марк - pconnect в php-cli не имеет смысла.

Ответы [ 3 ]

2 голосов
/ 20 апреля 2011

Единственное, что вы можете попробовать, это дать вашим детям подождать, пока друг друга не закончит свою работу. Таким образом, вы можете использовать одно и то же соединение с базой данных (при условии отсутствия проблем с синхронизацией). Но, конечно, у вас будет много процессов, что тоже не очень хорошо (по моему опыту, PHP имеет довольно большое использование памяти). Если наличие нескольких процессов, обращающихся к одному и тому же соединению с базой данных, не является проблемой, вы можете попытаться создать «группы» процессов, которые совместно используют соединение. Таким образом, вам не нужно ждать, пока не завершится каждое задание (вы можете выполнить очистку после завершения всей группы), и у вас также не будет много подключений ..

Вы должны спросить себя, действительно ли вам нужно соединение с базой данных для ваших рабочих процессов. Почему бы не позволить родителю получить данные и записать результаты в файл?

Если вам нужно соединение, вы должны рассмотреть возможность использования другого языка для работы. PHP сам по себе не является «типичным» вариантом использования (он был добавлен в 4.3), и многопроцессорность - это скорее взлом, чем поддерживаемая функция.

0 голосов
/ 19 августа 2017

Мой совет (из личного опыта по той же проблеме) - закрыть соединение до pcntl_fork(), а затем при необходимости открыть новые соединения в родительском и / или дочернем процессах.

Если вы открываете новое соединение в родительском процессе , затем необходимо заблокировать сигнал SIGCHLD (используя pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD)).В дочерних процессах не требуется особой заботы (кроме случаев, когда они также запускают своих собственных детей, становясь родителями таким образом.)

SIGCHLD - это сигнал, который получает родительский процесс, когда один из его дочерних элементов завершает работу..

Во время связи с сервером клиентская библиотека MySQL использует nanosleep(), чтобы приостановить выполнение программы на некоторое время.Функции sleep() возвращаются, когда время проходит, но они также возвращают до того, как пройдет время, если процесс получит сигнал, пока он приостановлен.

Когда nanosleep() возвращается из-за сигнала (т. Е. До того, как прошло достаточно времени), библиотека MySQL сбивается с толку и сообщает об ошибке «Сервер MySQL исчез», и соединение больше не может использоваться.Это ложная тревога, сервер MySQL все еще там ожидает запросов, но код клиента дурачит сигнал, полученный в неправильный момент.

Если вы заинтересованы в получении сигнала SIGCHLD, тогда вы можетезаблокируйте его перед выполнением запроса MySQL, а затем снова разблокируйте (чтобы избежать его получения во время связи с сервером MySQL.

Также прочитайте этот ответ и этот ответ Iписал по схожим вопросам (это та же информация, но с более подробными объяснениями)

0 голосов
/ 20 апреля 2011

Если ребенок вызывает exec () или _exit () довольно быстро, вы в порядке.Проблема в том, что ребенок остается рядом с копиями дескрипторов файлов.Это может хорошо сработать.

...