trait MultiProcessTrait
{

    protected $processes = [];

    protected $maxFork = 14;


    /**
     * @param $action \Closure
     * @param array $params
     */
    public function fork($action, $params = [])
    {
        $this->processes[] = [
            "action" => $action,
            "params" => $params
        ];
    }

    protected $runningProcess = [];

    public function waitProcessRun()
    {
        while (count($this->runningProcess) > 0) {
            $mypid = pcntl_waitpid(-1, $status, WNOHANG);
            foreach ($this->runningProcess as $key => $pid) {
                if ($mypid == $pid || $mypid == -1) {
                    echo "child $key completed\n";
                    unset($this->runningProcess[$key]);
                    //判断是否还有未fork进程
                    $this->runOne();
                }
            }
        }
    }

    public function runOne()
    {
        $process = array_shift($this->processes);
        if ($process) {
            $pid = pcntl_fork();
            if ($pid == -1) {
                die("could not fork");
            } elseif ($pid) {
                $this->runningProcess[$pid] = $pid;
                echo "create child: $pid \n";
            } else {
                //执行子进程
                call_user_func_array($process['action'], $process['params']);
                exit;// 一定要注意退出子进程,否则pcntl_fork() 会被子进程再fork,带来处理上的影响。
            }
        }
    }

    public function runProcess()
    {
        if (empty($this->processes)) {
            return;
        }

        for ($i = 0; $i < $this->maxFork; $i++) {
            $this->runOne();
        }

        $this->waitProcessRun();

    }

}