每每咱們會碰到一個狀況,須要寫一個腳本,這個腳本要處理的數據量極大,單進程處理腳本很是慢,那麼這個時候就會想到使用多進程或者多線程的方式了。php
我習慣使用多進程的方式,php中使用多進程的時候須要使用pcntl,pcntl的使用能夠看這個PHP的pcntl多進程html
可是這裏有一個問題,一個主進程把任務分紅n個部分,而後把任務分配給多個子進程,可是任務多是有返回值的,全部的子進程處理完返回值之後須要把返回值返回給主進程。redis
這個就涉及到了進程間通訊了。進程間通訊可使用的方法固然不少了,好比用redis,用數據庫,用文件等。數據庫
php中最簡單的要算shmop相關函數了。json
那怎麼讓一個類很容易有多進程處理的能力呢?可使用php的trait,建立一個PcntlTrait,全部須要有多進程處理功能的類就use 這個trait就行。數組
PcntlTrait代碼以下:多線程
<?php namespace App\Console\Commands; trait PcntlTrait { private $workers = 1; public function worker($count) { $this->workers = $count; } public function pcntl_call($all, \Closure $callback) { $perNum = ceil(count($all) / $this->workers); $pids = []; for($i = 0; $i < $this->workers; $i++){ $pids[$i] = pcntl_fork(); switch ($pids[$i]) { case -1: echo "fork error : {$i} \r\n"; exit; case 0: $data = []; try { $data = $callback(array_slice($all, $i * $perNum, $perNum)); } catch(\Exception $e) { echo ($e->getMessage()); } $shm_key = ftok(__FILE__, 't') . getmypid(); $data = json_encode($data); $shm_id = shmop_open($shm_key, "c", 0777, strlen($data) + 10); shmop_write($shm_id, $data, 0); shmop_close($shm_id); exit; default: break; } } // only master process will go into here $ret = []; foreach ($pids as $i => $pid) { if($pid) { pcntl_waitpid($pid, $status); $shm_key = ftok(__FILE__, 't') . $pid; $shm_id = shmop_open($shm_key, "w", 0, 0); $data = trim(shmop_read($shm_id, 0, shmop_size($shm_id))); $data = json_decode($data, true); $ret = array_merge($ret, $data); @shmop_close($shm_id); @shmop_delete($shm_id); } } return $ret; } }
它有兩個參數,第一個參數爲傳入數組,第二個參數爲數組處理函數。函數
它的具體使用經過下面這個測試用例能夠看出:測試
<?php use App\Console\Commands\PcntlTrait; class PcntlImp { use PcntlTrait; } class TestPcntlTrait extends \TestCase { public function setup() { $this->createApplication(); } public function testPcntlCall() { $arr = [1,2,3,4,5,6,7,8,9,10]; $imp = new \PcntlImp(); $imp->worker(2); $data = $imp->pcntl_call($arr, function($info){ if (empty($info)){ return []; } $ret = []; foreach ($info as $item) { $ret[] = $item * $item; } return $ret; }); $this->assertEquals(10, count($data)); $this->assertEquals(25, $data[4]); } }
很是方便~~this