我想要一个通过MySQL表并产生子进程的“永恒”进程。伪代码:
while(true)
$rows = SELECT * FROM workers
foreach($rows as $row){
DELETE $row->id
spawn_child($row->id)
}
sleep(5)
}
function spawn_child($id){
$pid = pcntl_fork()
if($pid <0){
//err
}elseif($pid == 0){
//child
exec("worker_program $id");
exit();
}elseif($pid > 0){
//parent
}
}
问题是,当子进程从worker_program返回并退出时,它会关闭显然共享的mysql-handle,因此父进程会得到一个“ Msql服务器消失” - 错误。
我该如何解决这个问题?这是一个设计错误吗?
如何在PHP中生成和分离进程,而不共享任何数据库资源等,以便孩子可以自由退出?
(我已经尝试过:setsid和forking,再次使用'worker_program &
'调用工作人员而不是在php中分叉,但这似乎根本不起作用(很奇怪?)。我正在使用PDO。另外在php.net的人说这个行为不是bug。这是在osx和php5.3(以及debian)上。)
参考文献:
php.net/bug:"Parent process lost MySQLi connection after child process gone"
更新/变通方法
所以我终于找到了解决这个问题的方法。有效的方法是使用popen
来生成工作进程。这样看起来似乎是一个完全“新鲜”的过程,没有任何共享。然后我让孩子做分叉和分离。因此,在主进程中,而不是pcntl_fork
或exec
:
$p = popen("worker_program $arg","r");
sleep(1); //give it time to detach (won't work otherwise. Any other ideas?)
pclose($p);
然后在工人计划中:
#!/usr/bin/env php
<?php
//fully detach from parent, as proposed by the 'gurus'
//(Why can't this be done with only one fork?)
if(pcntl_fork()) {
exit();
}
posix_setsid();
if(pcntl_fork()) {
exit();
}
...
答案 0 :(得分:2)
如何使用持久的MySQL连接。当你知道自己已经完成时关闭它。
$conn = new mysqli("p:".$dbhost, $dbuser, $dbpass, $dbname);
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass,
array(PDO::ATTR_PERSISTENT => true));
答案 1 :(得分:1)
如果在子进程中显式取消设置数据库句柄,那么如何在子出口处关闭它?父级应该保留它的句柄链接,因此链接可能不会被关闭。
答案 2 :(得分:0)
这些都不适合我。我这样做了:
// php execl type behaviour, execute and leave ...
// the args may be passed to $command or $args
// ekerner@ekerner.com.au
function execl($command, $args = array())
{
$command = escapeshellarg($command);
foreach ($args as $arg)
$command .= ' ' . escapeshellarg($arg);
exec($command . ' 2>/dev/null >&- /dev/null &');
}