misterion / ko-process
简单的pcntl fork包装和进程管理器
Requires
- php: >=5.4.0
Requires (Dev)
- php-mock/php-mock-phpunit: 0.2
- phpunit/phpunit: ~4.0.0
Suggests
- ext-pcntl: *
- ext-posix: *
- ext-proctitle: *
- ext-sysvsem: Required for using the Semaphore class
- ext-sysvshm: Required for using the SharedMemory class
README
Ko-Process 允许轻松进行可调用的分叉。它是对PHP扩展PCNTL的fork部分的对象封装。后台进程、从控制终端断开进程、信号和退出代码以及简单的通过共享内存的IPC。这是一个经过充分测试的库,用于实际世界的高负载项目。
安装
需求
PHP >= 5.4
pcntl extension installed
posix extension installed
通过Composer
安装库的推荐方法是 composer。您可以在Packagist上查看包信息。
{ "require": { "misterion/ko-process": "*" } }
不使用composer?
只需克隆存储库并注意命名空间 Ko
的自动加载。
使用方法
基本使用方法如下
$manager = new Ko\ProcessManager(); $process = $manager->fork(function(Ko\Process $p) { echo 'Hello from ' . $p->getPid(); })->onSuccess(function() { echo 'Success finish!'; })->wait();
如果需要等待所有分叉进程
$manager = new Ko\ProcessManager(); for ($i = 0; $i < 10; $i++) { $manager->fork(function(Ko\Process $p) { echo 'Hello from ' . $p->getPid(); sleep(1); }); } $manager->wait();
进程标题?
是的,ProcessManager
和 Process
都可以使用 setProcessTitle
函数更改进程标题。或者,您也可以使用 trait Ko\Mixin\ProcessTitle 将此功能添加到任何您想要的类中。请注意 ProcessManager::onShutdown
- 如果 ProcessManager
捕获 SIGTERM
,则可以设置可调用的处理程序。处理程序将在子进程关闭之前被调用。我们使用 demonize
从终端断开连接。运行示例代码
$manager = new Ko\ProcessManager(); $manager->demonize(); $manager->setProcessTitle('I_am_a_master!'); $manager->onShutdown(function() use ($manager) { echo 'Catch sigterm.Quiting...' . PHP_EOL; exit(); }); echo 'Execute `kill ' . getmypid() . '` from console to stop script' . PHP_EOL; while(true) { $manager->dispatch(); sleep(1); }
并使用 ps aux|grep I_am_a_master
或 top
查看您在Linux进程列表中的进程标题。
生成
在创建主-子进程模式的应用程序时,您应该注意子进程要保持活跃。spawn
函数可以帮助您实现这一点 - 一旦 spawn
,在退出时带有一些错误代码后,它将保持分叉进程活跃。
$manager = new Ko\ProcessManager(); for ($i = 0; $i < 10; $i++) { $manager->spawn(function(Ko\Process $p) { echo 'Hello from ' . $p->getPid(); sleep(1); exit(1); //exit with non 0 exit code }); } $manager->wait(); //we have auto respawn for 10 forks
让我们解释您正在编写基于PhpAmqpLib\AMPQ的队列工作者。因此,您可以编写如下内容
use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; $manager = new Ko\ProcessManager(); $manager->setProcessTitle('Master:working...'); $manager->spawn(function(Ko\Process $p) { $connection = new AMQPConnection('localhost', 5672, 'guest', 'guest'); $channel = $connection->channel(); $channel->queue_declare('hello', false, true, false, false); $callback = function($msg) use (&$p) { $p->setProcessTitle('Worker:processJob ' . $msg->body); //will execute our job in separate process $m = new Ko\ProcessManager(); $m->fork(function(Ko\Process $jobProcess) use ($msg) { $jobProcess->setProcessTitle('Job:processing ' . $msg->body); echo " [x] Received ", $msg->body, "\n"; sleep(2); echo " [x] Done", "\n"; })->onSuccess(function() use ($msg){ //Ack on success $msg->delivery_info['channel'] ->basic_ack($msg->delivery_info['delivery_tag']); })->wait(); $p->setProcessTitle('Worker:waiting for job... '); //IMPORTANT! You should call dispatch() them self to process pending signals. $p->dispatch(); if ($p->isShouldShutdown()) { exit(); } }; $channel->basic_qos(null, 1, null); $channel->basic_consume('hello', '', false, false, false, false, $callback); while(count($channel->callbacks)) { $channel->wait(); } $channel->close(); $connection->close(); }); $manager->wait();
共享内存和信号量
Ko\SharedMemory
使用 Semaphore
进行内部锁定,因此可以安全地用于进程间通信。共享内存实现了 \ArrayAccess
和 \Countable
接口,因此可以像数组一样访问。
$sm = new SharedMemory(5000); //allocate 5000 bytes $sm['key1'] = 'value'; echo 'Total keys is' . count($sm) . PHP_EOL; echo 'The key with name `key1` exists: ' . isset($sm['key1'] . PHP_EOL; echo 'The value of key1 is ' . $sm['key1'] . PHP_EOL; unset($sm['key1']); echo 'The key with name `key1` after unset exists: ' . isset($sm['key1'] . PHP_EOL;
您可以使用 Semaphore
进行进程间锁定
$s = new Semaphore(); $s->acquire(); //do some job $s->release(); //or $s->tryExecute(function() { //do some job });
致谢
Ko-process 是由 Nikolay Bondarenko(misterionkell at gmail.com)作为GameNet项目的一部分编写的。
许可证
在MIT许可证下发布。