线程思想php,Pthreads扩展实现PHP多线程学习笔记

一、关于pthreads扩展

PHP本身不支持多线程,如果想再CLI模式下实现多线程,需要通过扩展pthreads。pthreads 是一组允许用户在PHP中使用多线程技术的面向对象的API。基于Posix Threads。

注:

POSIX(Portable Operating System Interface)是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列互相关联的标准的总称, 也叫可移植操作系统接口。

POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程。Windows操作系统也有其移植版pthreads-win32。

二、编译安装Pthreads

0、下载扩展

git clone https://github.com/krakjoe/pthreads.git

1、需要确认PHP是指定线程安全的方式编译的

/usr/local/php/bin/php --info | grep Thread

Thread Safety => enabled

如果不是线程安全的需要带上参数–enable-maintainer-zts,重新编译。

2、编译按照pthreads扩展

cd pthreads/

/usr/local/php/bin/phpize

./configure --with-php-config=/usr/local/php/bin/php-config

make && make install

4、php.ini中添加扩展

把pthreads.so添加到php.ini文件中

/usr/local/php/bin/php -m | grep pthread

pthreads

5、测试

以下代码保存文件pthreads.php

$thread = new class extends Thread {

public function run() {

echo "Hello World\n";

}

};

$thread->start() && $thread->join();

执行以上代码

/usr/local/php/bin/php pthreads.php

Hello World

三、多线程原理

0、TSRM机制

多线程模式下,多个线程共用一个进程的地址空间,即多个线程共享一个全局变量,这个时候就会产生竞争,也就是常说的这个全局变量是非线程安全的。PHP引入了一个TSRM(Thread-Safe Resource Manager)机制来解决线程安全问题。

这个机制的主要思想是:对于多线程模型来说,每当一个新的线程被创建,就单独的分配一块内存,这块内存存储着一个全局变量的副本。而这块内存会被一个Vector串起来,由Zend统一管理。(参加风雪之隅:揭秘TSRM(Introspecting TSRM))

1、线程类

在pthread扩展中,提供了创建多线程应用需要的全套工具。主要包含以下几个类,Threaded、Thread、Worker、Pool、Mutex等。

1.0、Threaded

提供多线程操作的基本功能。主要的是run方法, 每个线程都要实现此方法,线程开始运行后,此方法中的代码会自动执行;

1.1、Thread

继承了Threaded类,实现了run方法。Thread类中常用方法

Thread::start() 开始运行一个新线程,并且执行继承的run方法。

Thread::getThreadId() 获取当前线程ID。

Thread::join() 等待线程结束。

Thread::kill() 强制线程结束。

注:创建自己的线程类,通常直接继承Thread类。

1.2、Mutex(pthread 小于2.0版本,2.0以上使用Threaded::synchronized)

互斥锁相关功能。常用方法

Mutex::create 创建一个互斥锁

Mutex::lock 给互斥量加锁

Mutex::unlock 释放互斥量上的锁

Mutex::destroy 释放互斥锁

四、多线程实践

一、一个进程中创建多个线程执行打印操作

0、代码(以下保存文件multi_thread.php)

class workerThread extends Thread {

private $i = null;

public function __construct($i) {

$this->i = $i;

}

public function run() {

printf("%s is Thread #%lu, Pid=%s\n", __CLASS__, $this->getThreadId(), getmypid());

while(true) {

echo $this->i, PHP_EOL;

sleep(10);

}

}

}

for($i = 0; $i < 10; $i++) {

$workers[$i] = new workerThread($i);

$workers[$i]->start();

}

1、执行结果

[root@izj6cfhaw27k49x8usszs3z thread]# php7 multi_thread.php

workerThread is Thread #140040849848064, Pid=6554

0

workerThread is Thread #140040764126976, Pid=6554

1

workerThread is Thread #140040755734272, Pid=6554

2

workerThread is Thread #140040747341568, Pid=6554

3

workerThread is Thread #140040738948864, Pid=6554

4

workerThread is Thread #140040726378240, Pid=6554

5

workerThread is Thread #140040713795328, Pid=6554

6

workerThread is Thread #140040361473792, Pid=6554

7

workerThread is Thread #140040353081088, Pid=6554

8

workerThread is Thread #140040344688384, Pid=6554

9

并行的打印出了上面的结果,等9后推出。

2、思考

把run方法中while去掉,也是同样的结果,为啥没有进入while轮询呢

二、多线程实现计数器程序

0、代码(以下代码保存在文件pthread_multi.php)

$counter = 0;

$handle = fopen("/tmp/counter.txt", "w");

fwrite($handle, $counter );

fclose($handle);

class CounterThread extends Thread {

public function __construct($mutex = null) {

$this->mutex = $mutex;

$this->handle = fopen("/tmp/counter.txt", "w+");

}

public function run() {

if($this->mutex)

$locked = Mutex::lock($this->mutex);

$counter = intval(fgets($this->handle));

$counter++;

rewind($this->handle);

fputs($this->handle, $counter);

printf("Thread #%lu says: %s\n", $this->getThreadId(), $counter);

if($this->mutex)

Mutex::unlock($this->mutex);

}

public function __destruct(){

fclose($this->handle);

}

}

//没有互斥锁

for ($i = 0; $i < 10; $i++) {

$threads[$i] = new CounterThread();

$threads[$i]->start();

}

// 加入互斥锁

$mutex = Mutex::create(true);

for ($i = 0; $i < 50; $i++) {

$threads[$i] = new CounterThread($mutex);

$threads[$i]->start();

}

Mutex::unlock($mutex);

for ($i = 0; $i < 50; $i++) {

$threads[$i]->join();

}

Mutex::destroy($mutex);

1、执行

使用到了Mutex类,需要在pthread2.0以下版本使用。

php pthread_multi.php

查看pthread版本

/usr/local/php/bin/php --info | grep -C 10 -i 'pthread'

pthreads

Version => 3.2.1dev

执行报错”zend_mm_heap corrupted”(更多solutin点击stackoverflow What does zend_mm_heap corrupted mean)

在命令行执行如下命令

export USE_ZEND_ALLOC=0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值