簡體   English   中英

在pcntl_fork之后,如何在父進程中保持mysql連接?

[英]How do I keep my mysql connection in the parent process after pcntl_fork?

大家都知道,當您使用fork時,孩子會得到所有東西的副本,包括文件和網絡描述符man fork

在PHP中,當使用pcntl_fork時,將復制所有使用mysql_connect創建的連接,這有點問題-php docsSO問題 這種情況下的常識說,關閉父級連接,創建新的連接,讓孩子使用舊的連接。 但是,如果說父母需要在幾秒鍾之內創造出許多孩子呢? 在這種情況下,您最終會創建大量新連接-每一批叉子都有一個。

這在代碼中是什么意思:

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中那樣工作。 正如Marc所注意到的-php-cli中的pconnect沒有意義。

您唯一可以嘗試的方法就是讓您的孩子等到另一個孩子都完成工作為止。 這樣,您可以使用相同的數據庫連接(前提是不存在任何同步問題)。 但是,當然,您將有很多過程,這些過程也不是很好(根據我的經驗,PHP具有相當大的內存使用量)。 如果讓多個進程訪問同一數據庫連接不是問題,則可以嘗試將共享連接的進程“分組”。 因此,您不必等到每個作業都完成時(可以在整個工作組完成后進行清理),並且也沒有太多的聯系。

您應該問問自己,您的工作進程是否真的需要數據庫連接。 為什么不讓父項獲取數據並將結果寫入文件?

如果確實需要連接,則應考慮使用另一種語言進行作業。 PHP cli本身不是“典型的”用例(它是在4.3中添加的),並且多處理更多的是hack,而不是受支持的功能。

我的建議(來自同一問題的個人經驗)是在pcntl_fork()之前關閉連接,然后根據需要在父進程和/或子進程中打開新的連接。

如果您在父進程中打開新連接則必須阻止SIGCHLD信號(使用pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD) )。在子進程中無需特別注意(除非它們還啟動了自己的子進程,成為這樣的父母。)

SIGCHLD是其子進程之一完成時由父進程接收的信號。

在與服務器通信期間,MySQL客戶端庫使用nanosleep()暫停程序的執行一段時間。 當時間流逝時, sleep()函數將返回,但如果進程在掛起時接收到信號,它們也會時間流逝之前返回。

nanosleep()由於信號而返回時(即在經過足夠的時間之前),MySQL庫會感到困惑並報告錯誤“ MySQL服務器已消失”,並且該連接無法再使用。 這是一個錯誤的警報,MySQL服務器仍然在那里等待查詢,但是客戶端代碼被錯誤時間到達的信號所欺騙。

如果您有興趣接收SIGCHLD信號,則可以在運行MySQL查詢之前將其阻止,然后再次取消阻止(以避免在與MySQL服務器通信期間收到該信號)。

還請閱讀此答案以及我在類似問題上寫的答案 (具有相同的信息,但有更多詳細信息和解釋。)

如果孩子相當快地調用exec()或_exit(),那就沒問題了。 問題是孩子是否堅持並堅持使用文件描述符的副本。

如果PHP具有用於此的API,則也可以使用posix_spawn。 可能效果很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM