php pthreads 使用的那些事儿

分类:PHP |

1. 编译安装PHP

下载: wget http://cn2.php.net/distributions/php-5.6.30.tar.gz

./configure --prefix=/opt/php56-zts --enable-pcntl --with-config-file-path=/opt/php56-zts/etc/ --with-libdir=lib64 --with-curl --with-mcrypt --with-openssl --enable-bcmath --enable-maintainer-zts
make && make install

2. 编译安装 Pthreads 

下载: wget http://pecl.php.net/get/pthreads-2.0.5.tgz

./configure --with-php-config=/opt/php56-zts/bin/php-config
make && make install

注: 请不要使用最新版本的 pthreads-3.1.6.tgz, 此版本浪费了我 一天时间, 也没安装上去 , 因为3.x 是对php7.x的版本的

Pthreads 官方文档:

http://php.net/manual/zh/book.pthreads.php

官方简单例子:

<?php
class My extends Thread{
    function run(){
        for($i=1;$i<10;$i++){
            echo Thread::getCurrentThreadId() .  "\n";
            sleep(2);     // <------
        }
    }
}

for($i=0;$i<2000;$i++){
    $pool[] = new My(); 
}
foreach($pool as $worker){
    $worker->start();
}
foreach($pool as $worker){
    $worker->join();
}
?>


<?php
class Request extends Thread {
    public $url;
    public $data;
    public function __construct($url) {
        $this->url = $url;
    }
    public function run() {
        // 线程处理一个耗时5秒的任务
        for($i=0;$i<5;$i++) {
            echo '线程: '.date('H:i:s')."\n";
            sleep(1);
        }
        $response = file_get_contents($this->url);
        if ($response) {
            $this->data = array($response);
        }
        echo "线程: 任务完成\n";
    }
}
$request = new Request('hello.html');
// 运行线程:start()方法会触发run()运行
if ($request->start()) {
    // 主进程处理一个耗时10秒的任务,此时线程已经工作
    for($i=0;$i<10;$i++) {
        echo '进程: '.date('H:i:s')."\n";
        sleep(1);
    }
    // 同步线程并输出线程返回的数据
    $request->join();
    echo '线程返回数据: '.$request->data[0];
}
/*
如果顺序执行,合计时间将是15秒,借助线程,则只需10秒.
生成文件: echo 'Hello' > hello.html
运行计时: time php req.php 
查看线程: ps -efL|head -n1 && ps -efL|grep php
*/


查看线程:  

ps -efL|head -n1 && ps -efL|grep php

UID为User ID.

PID为processid,进程标识符

PPID为 parent processid,父进程标识符2,

LWP为light weight process orthread, 轻量级进程,即线程标识符

NLWP为,number oflwps(threads) in the process, 线程的数量


不错的实例, 对理解php多线程很有帮助:

<?php
class vote extends Thread {
    public $res    = '';
    public $url    = array();
    public $name   = '';
    public $runing = false;
    public $lc     = false;
    public function __construct($name) {
        $this->res    = '暂无,第一次运行.';
        $this->param    = 0;
        $this->lurl   = 0;
        $this->name   = $name;
        $this->runing = true;
        $this->lc     = false;
    }
    public function run() {
        while ($this->runing) {
            if ($this->param != 0) {
                $nt          = rand(1, 10);
                echo "线程[{$this->name}]收到任务参数::{$this->param},需要{$nt}秒处理数据.\n";
                $this->res   = rand(100, 999);
                sleep($nt);
                $this->lurl = $this->param;
                $this->param   = '';
            } else {
                echo "线程[{$this->name}]等待任务..\n";
            }
            sleep(10);
        }
    }
}
//这里创建线程池.
$pool[] = new vote('a');
$pool[] = new vote('b');
$pool[] = new vote('c');
//启动所有线程,使其处于工作状态
foreach ($pool as $w) {
    $w->start();
}
//派发任务给线程
for ($i = 1; $i < 10; $i++) {
    $worker_content = rand(10, 99);
    while (true) {
        foreach ($pool as $worker) {
            //参数为空则说明线程空闲
            if ($worker->param=='') {
                $worker->param = $worker_content;
                echo "[{$worker->name}]线程空闲,放入参数{$worker_content},上次参数[{$worker->lurl}]结果[{$worker->res}].\n";
                break 2;
            }
        }
        sleep(1);
    }
}
echo "所有线程派发完毕,等待执行完成.\n";
//等待所有线程运行结束
while (count($pool)) {
    //遍历检查线程组运行结束
    foreach ($pool as $key => $threads) {
        if ($worker->param=='') {
            echo "[{$threads->name}]线程空闲,上次参数[{$threads->lurl}]结果[{$threads->res}].\n";
            echo "[{$threads->name}]线程运行完成,退出.\n";
            //设置结束标志
            $threads->runing = false;
            unset($pool[$key]);
        }
    }
    echo "等待中...\n";
    sleep(1);
}
echo "所有线程执行完毕.\n";