PHP pcntl_fork实现多线程

之前去其他公司面试遇到了面试官提了个之前没试用过的php多线程处理,让我懵逼了一下,不能自己了。回来之后马上脑补,翻了很多网上资料终于理解了,pcntl_fork多线程,但是本质上还是单核处理的,即使是多线程,也是只能使用单核来处理,还是有上线的限制。

php语言本身是不支持多线程,但php提供了pcntl_fork 函数可以帮助我们实现多线程运行:

pcntl_fock函数官方介绍:
说明
int pcntl_fork ( void )

pcntl_fork()函数创建一个子进程,这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。fork怎样在您的系统工作的详细信息请查阅您的系统 的fork(2)手册。

返回值
成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。

范例
Example #1 pcntl_fork() 示例

$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
    //错误处理:创建子进程失败时返回-1.
     die('could not fork');
} else if ($pid) {
     //父进程会得到子进程号,所以这里是父进程执行的逻辑
     pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
     //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}

多线程处理工具类实现:

// 多线程处理基类.
// FileName : Thread.php
abstract class Thread
{
    // 线程数量
    private $threadNum = 10;
    public static $instance = null;
     
    private function __construct()
    {
         
    }
     
    // 单例对象实现
    // @return $instance
    public static function getInstance($threadNum = 10)
    {
        if (self::$instance == null) {
            self::$instance = new static;
        }
        if ($threadNum > 0) {
            self::$instance->threadNum = $threadNum;
        }
        return self::$instance;
    }
     
    // 脚本启动前处理.
    public function beforeRun()
    {
         
    }
     
    // 启动脚本.
    public function start()
    {
        $this->beforeRun();
        if (function_exists('pcntl_fork') && $this->getThreadNum() > 1) {
            for ($x = 0; $x < $this->getThreadNum() ; $x++) {
                $pid = pcntl_fork();
                if ($pid == -1) {
                    echo "subprocess create faild!".PHP_EOL;
                } elseif ($pid) {
                    $this->run();
                    exit();
                } else {
                    pcntl_wait($status);
//pcntl_waitpid($pid, $status, WNOHANG);//异步不等待子进程返回
                }
            }
        } else {
            $this->run();
        }
        $this->afterRun();
    }
     
    // 脚本运行后处理.
    public function afterRun()
    {
         
    }
     
    // 获取进程数.
    public function getThreadNum()
    {
        return $this->threadNum;
    }
     
    // 设置进程数.
    public function setThreadNum($num)
    {
        $this->threadNum = $num;
    }
     
    // 抽象的业务方法.
    public abstract function run(); 
}

应用实现多线程:

// 业务多线程处理.
// FileName : Test.php
 class Test extends Thread
 {
    // 同时运行的进程数.
    const PROGRESS_NUM = 1;
      
    // Process.
    // @return void
    public function run()
    {
        // TODO 业务逻辑处理
    }
 }
 // 执行多线程业务处理.
 Test::getInstance(Test::PROGRESS_NUM)->start();

其他参考:http://blog.csdn.net/lgg201/article/details/5996444

 

Leave a comment