我有一个PHP脚本,我正在Ubuntu Linux机器上运行。该脚本使用pcntl_fork()函数生成多个进程,并使用pcntl_waitpid()函数记录它们被终止。它经常产生这些(我估计大约40-50 /秒),但是这些过程每次都立即死亡(我尝试了exit()和posix_kill(${pid}, SIGKILL)都无济于事)。该脚本可以在几秒钟内正常工作(取决于,10~30秒),但不可避免地会暂停并停止创建“子元素”进程。由于脚本导致机器上的内存使用量不会增加,但是当脚本暂停时,机器上的cpu会缓慢增加,直到我强制使用Ctrl-C终止脚本。每个进程都是为了解析一行文本并最终将其保存到一个文件中。出于测试目的,我只是在创建子进程后立即退出。在一次测试中,大约有1400个进程在脚本冻结前成功启动并被杀死,尽管我说过这个范围。
我知道一台机器有一个ulimit,但我相信我读了它,它限制了并发进程的数量。由于该脚本一旦创建就会终止子进程,因此我对发生的事情感到困惑。以下是我当前的ulimit配置(ulimit -a)的输出:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 29470
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 29470
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimitedPHP中是否存在全局限制,用于确定脚本执行期间创建的进程总数? **请记住,这些子进程会立即死亡,所以我不认为这是造成系统资源窃取的进程数量不受限制的问题。
这里有一些源代码:
我用这个初始化fork
$this->process_control->fork(array($this, "${FUNCTION_NAME}"), array(STRING_LINE), false);过程分叉函数。在这种情况下,$ callback是要在适当的类中调用的函数的名称。 $ params是传递给$ callback中指定的函数的一组参数。
public function fork ($callback, $params = null, $hang = true)
{
$this->logger->write_log('log', "Entered fork function!");
// Evaluate the return value of the fork
switch ($pid = pcntl_fork()) {
case -1: // Failed
$this->logger->write_log('error', "Could not fork!");
exit(1);
break;
case 0: // Child created succesfully
$this->logger->write_log('log', "Entered child function!");
$this->logger->write_log('log', 'child ' . posix_getpid() . ' started');
if (empty($callback)) {
$this->logger->write_log('warn', "Callback empty, nothing to do!");
exit(1);
}
if (is_array($callback) && is_array($params)) {
if (!call_user_func_array($callback, $params)) {
$this->logger->write_log('error', "Daemonized process returned false!");
exit(1);
} else {
exit(0);
}
} else {
if (!call_user_func($callback, $params)) {
$this->logger->write_log('error', "Daemonized process returned false!");
exit(1);
} else {
exit(0);
}
}
break;
default: // Parent
$this->logger->write_log('log', "Entered parent function!");
if ($hang != true) {
$this->wait($pid, false);
} else {
$this->wait($pid);
}
break;
}
}
public function wait($p_id, $hang = true)
{
if ($hang) {
$pid = pcntl_waitpid($p_id, $status);
} else {
$pid = pcntl_waitpid($p_id, $status, WNOHANG);
}
switch($pid) {
case -1:
case 0:
$this->logger->write_log('log', "child exited");
break;
default:
$this->logger->write_log('log', "child $pid exited");
break;
}
}实际上处理文本行的功能。文本行是JSON对象:
public function FUNCTION_NAME($line) {
$this->logger->write_log('info', 'entered FUNCTION_NAME function');
$start_time = microtime(true);
try {
# check to see that the JSON line is not malformed
$line_array = json_decode($line, true);
if (!isset($line_array)) {
throw new Exception('Could not successfully process line');
}
# save the contents to disk
if (!file_put_contents(FILE_NAME, $line, LOCK_EX)) {
throw new Exception('file could not be saved');
}
$this->logger->write_log('info', 'saved line');
return true;
} catch (Exception $e) {
$this->logger->write_log('error', $e->getMessage());
$this->logger->write_log('error', '----------------------------------------------------');
$this->logger->write_log('error', var_export($line, true));
$this->logger->write_log('error', '----------------------------------------------------');
file_put_contents(ERROR_SRC_FILE, $line, FILE_APPEND);
return false;
}
}对不起,如果这是太多的代码,让我知道任何问题