php 多进程 生产环境,PHP多进程

php多进程核心

1.创建一个子进程

$pid = pcntl_fork();

//父进程和子进程都会执行下面代码

if ($pid > 0) {

//父进程会得到子进程号,所以这里是父进程执行的逻辑

pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程

} elseif ($pid == 0) {

//子进程得到的$pid为0, 所以这里是子进程执行的逻辑

} else {

//错误处理:创建子进程失败时返回-1

die(‘could not fork’);

}

//挂起主进程,等待一个子进程退出或被信号打断

int pcntl_wait ( int &$status [, int $options = 0 ] )

2.创建多个进程

for ($i = 0; $i 0) {

//父进程会得到子进程号,所以这里是父进程执行的逻辑

} elseif ($pid == 0) {

//子进程得到的$pid为0, 所以这里是子进程执行的逻辑

exit(0);

} else {

//错误处理:创建子进程失败时返回-1

die(‘could not fork’);

}

}

注意,创建多个子进程的时候,不能在主进程中加入 pcntl_wait($status),主进程执行到pcntl_fork后,会产生一个子进程,主进程和子进程会分开执行,当挂起主进程后,主进程会等待子进程结束后才继续执行下一个循环,所以会导致堵塞 子进程处理结束后必须加上exit(0)终止子进程,否则子进程将继续执行if之后的代码

3.多进程工作实例

for ($i = 0; $i 0) {

//父进程会得到子进程号,所以这里是父进程执行的逻辑

} elseif ($pid == 0) {

//子进程得到的$pid为0, 所以这里是子进程执行的逻辑

call_user_func(‘work_handler’);

exit(0);

} else {

//错误处理:创建子进程失败时返回-1

die(‘could not fork’);

}

}

function work_handler() {

//子进程执行的逻辑

}

信号

涉及到进程管理的几个信号量

//通知前台进程组终止进程

SIGINT

//供用户自定义

SIGUSR1

//供用户自定义

SIGUSR2

1.安装信号处理器

bool pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] )

//声明用于进程信号处理。如果注册了信号处理器,程序会每执行一行代码后自动检查是否有尚未处理的信号

declare(ticks = 1);

//安装信号处理器

pcntl_signal(SIGTERM, “sig_handler”);

pcntl_signal(SIGHUP, “sig_handler”);

pcntl_signal(SIGUSR1, “sig_handler”);

//或者

pcntl_signal(SIGUSR1, array($obj, “do_something”);

信号处理器,顾名思义是当信号产生后(信号产生有多种方式,有用户产生也有系统产生)执行的函数

2.定义信号处理函数

//信号处理函数

function sig_handler($signo)

{

switch ($signo) {

case SIGTERM:

//处理SIGTERM信号

exit;

break;

case SIGHUP:

//处理SIGHUP信号

break;

case SIGUSR1:

echo “Caught SIGUSR1…\n”;

break;

default:

//处理所有其他信号

}

}

//发送信号

bool posix_kill ( int $pid , int $sig )

注意,以上的安装信号和处理信号函数只是绑定发送信号后的处理程序,其实如果需要关闭进程仅需使用posix_kill($pid, SIGINT)

通过信号来控制进程

/**

* 安装信号处理器

* @return void

*/

protected function install_signal()

{

// stop

pcntl_signal(SIGINT, ‘signal_handler’, false);

// reload

pcntl_signal(SIGUSR1, ‘signal_handler’, false);

// status

pcntl_signal(SIGUSR2, ‘signal_handler’, false);

}

/**

* 信号处理函数

* @return void

*/

public function signal_handler($signal) {

switch ($signal) {

// stop

case SIGINT:

stop_all();

break;

// reload

case SIGUSR1:

echo “sreloadtop\n”;

break;

// show status

case SIGUSR2:

echo “status\n”;

break;

}

}

$_worker_pids = array();

//开启多进程

for ($i = 0; $i 0)

{

$_worker_pids[$pid] = $pid;

}

// 子进程

elseif(0 === $pid)

{

// 子进程逻辑

// 这里用0表示正常退出

exit(0);

}

else

{

exit(“fork one worker fail”);

}

}

/**

* 用信号依次关闭子进程

* @return void

*/

public function stop_all()

{

foreach ($_worker_pids as $worker_pid)

{

posix_kill($worker_pid, SIGINT);

}

}

install_signal()安装信号处理器,把信号处理函数signal_handler()和三个信号绑定,当进程出现SIGINT信号的时候,会调用stop_all()函数,stop_all()函数会逐一对$_worker_pids记录的进程发送SIGINT信号

一个多进程类

threads = [];

$this->ignoreErrors = false;

$this->memoryKey = round(microtime(true) * 1000);

}

/**

* Run some code in a thread.

*

* @param callable $func The function to execute

* @param array|mixed $args The arguments (or a single argument) to pass to the function

*

* @return int The pid of the thread created to execute this code

*/

public function call(callable $func, $args = null)

{

$pid = pcntl_fork();

if ($pid == -1) {

throw new \Exception(“Failed to fork”);

}

# If this is the child process, then run the requested function

if (!$pid) {

try {

if ($args === null) {

$func();

} else {

call_user_func_array($func, $args);

}

} catch(\Exception $e) {

$memory = shmop_open($this->memoryKey, “c”, 0644, static::SHARED_MEMORY_LIMIT);

$errors = shmop_read($memory, 0, static::SHARED_MEMORY_LIMIT);

$errors = trim($errors);

if ($errors) {

$errors .= “\n”;

}

$errors .= “Exception: ” . $e->getMessage() . ” (” . $e->getFile() . “:” . $e->getLine() . “)”;

shmop_write($memory, $errors, 0);

shmop_close($memory);

exit(1);

}

# Then we must exit or else we will end up the child process running the parent processes code

die();

}

$this->threads[$pid] = $pid;

return $pid;

}

/**

* Wait for the processes started via call().

*

* @param int $pid The pid to wait for, if none is passed then all threads created by this object will be waited for

*

* @return int The highest return status for each of the processes we’ve waited for

*/

public function wait($pid = null)

{

if ($pid) {

$threads = [$pid];

} else {

$threads = $this->threads;

}

$error = false;

$status = 0;

foreach ($threads as $pid) {

pcntl_waitpid($pid, $status);

if ($status > 0) {

$error = $status;

}

unset($this->threads[$pid]);

}

if (!$this->ignoreErrors && $error) {

$memory = shmop_open($this->memoryKey, “a”, 0, 0);

$errors = shmop_read($memory, 0, static::SHARED_MEMORY_LIMIT);

shmop_delete($memory);

shmop_close($memory);

$error = “An error occurred within a thread, the return code was (” . $error . “)”;

if ($errors = trim($errors)) {

$error .= “\n” . $errors;

}

throw new \Exception($error);

}

return $status;

}

/**

* If no call to wait() is made, then we wait for the threads on destruct

*/

public function __destruct()

{

$this->wait();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值