在工作中,经常会用到将一大批数据分到多个进程中去处理的需求。于是自己写了一个简单的多进程类。方便以后使用,特在此总结一下:
初始化一个多进程模型:$processes = new Processes($processNumber);
$processNumber表示启动几个进程。
用多进程模型来运行指定的方法:$processes->run($object, $method, $data, $recall)
$object: 要运行的方法所处的对象
$method:要运行的对象的方法
$data:要处理的数据,必须为一个数组
$recall:回调的方法
注:此类库模型仅在Linux平台下可用。且安装php时必须--enable-pcntl。即已安装pcntl模块。
例如:我们要对0-100个数都做加1操作,我们启动五个进程,则有如下代码:
class Add {
public function run()
{
$data = array();
for ($i = 0; $i <= 10; $i++) {
$data[] = $i;
}
$processes = new Processes(5);
$processes->run($this, 'add', $data);
}
public function add($data)
{
foreach ($data as $row) {
echo ($row+1).PHP_EOL;
}
}
}
$add = new Add();
$add->run();
附:多进程模型类代码:
class Processes
{
/**
* 进程的个数
*
* @var intval
*/
protected $_number;
/**
* 已启动的进程个数
*
* @var intval
*/
protected $_forkedNumber;
/**
* 最大进程个数
*
* @var intval
*/
protected $_maxNumber;
/**
* 进程id列表
*
* @var array
*/
protected $_pids;
/**
* 初始化
*
* @param intval $maxNumber
* @return void
*/
public function __construct($maxNumber)
{
if ($maxNumber <= 1) {
throw new Exception('The num must above one');
}
$this->_forkedNumber = 0;
$this->_number = 0;
$this->_maxNumber = $maxNumber;
}
/**
* 获取进程的个数
*
* @return intval
*/
public function getNumber()
{
return $this->_number;
}
/**
* 获取进程的个数
*
* @return intval
*/
public function getForkedNumber()
{
return $this->_forkedNumber;
}
/**
* 获取最大进程的个数
*
* @return intval
*/
public function getMaxNumber()
{
return $this->_maxNumber;
}
/**
* 设置最大进程个数
*
* @return intval
*/
public function setMaxNumber($number)
{
$this->_maxNumber = $number;
}
/**
* 是否满了
*
* @return void
*/
public function isFull()
{
return $this->getForkedNumber() >= $this->getMaxNumber();
}
/**
* 开始工作
*
* @param object $model
* @param string $command
* @param array $data
* @param string $recall
* @return void
*/
public function run($model, $command, $data = array(), $recall = null)
{
if (!empty($data)) {
$data = array_chunk($data, ceil(count($data)/$this->getMaxNumber()), true);
$this->setMaxNumber(count($data));
}
for ($i = 0; $i < $this->getMaxNumber(); $i++) {
$pid = pcntl_fork();
if ($pid < 0) {
return false;
} elseif ($pid == 0) {
$model->$command($data[$i]);
exit(0);
} else {
$this->_pids[$pid] = true;
$this->_number++;
$this->_forkedNumber++;
}
}
if ($this->isFull()) {
$this->wait();
if ($recall) {
$model->$recall();
}
exit(0);
}
}
/**
* 等候子进程运行完程序
*
* @return void
*/
public function wait()
{
$finNumber = 0;
$errNumber = 0;
while (true) {
$pid = pcntl_waitpid(-1, $state, WNOHANG|WUNTRACED);
if ($pid <= 0) {
usleep(100);
continue;
}
$finNumber++;
$this->_number--;
if ($this->_number <= 0) {
return true;
}
usleep(100);
}
}
}