PHP多线程扩展-parallel(一)
php其实也是有多线程的,比较有名的就是pthread 扩展,但是当我打开官网想学习一下,结果。
既然官方都放弃他了,那就看看parallel吧,百度谷歌了一下,几乎没人发文章….官网的说明全英文而且非常的简陋,凭着我的4级英语水平以及翻译软件勉强明白了几个核心api的使用…
安装
值得一提的是parallel扩展支持windows,从这点看就比 pthread 好多了,在cli是可以使用的,就是不知道在fpm下是否可以使用(经过测试无法再用于fpm)。
我直接在windows上测试的,windows上安装比较简单:
1.下载php7.2+,必须线程安全版本
2.下载 parallel 扩展
3.php_parallel.dll放到ext目录,php.ini加上extension=parallel(当然扩展目录也可自定义)
4.pthreadVC2.dll(扩展包里的)拖到php.exe同级,该目录添加环境变量。
php -m 运行查看是否存在 parallel 扩展
运行
相比pthread确实是简陋了不少,文档更简单,靠着一些常识理解了几个核心api。
runtime
创建一个运行对象
$thread=new \parallel\Runtime('G:\study\php\parallel\a.php');
参数是引导文件路径, parallel 创建线程的时候跟主线程是不共享代码的,也就是意味着新线程里没法使用原来代码里的类,所以需要传入一个引导文件,这个引导文件一般是autoload之类的自动加载文件。
runtime::run
重头戏了,运行一个线程。参数是一个闭包。
<?php
$r1=new \parallel\Runtime('G:\study\php\parallel\a.php');
$r2=new \parallel\Runtime('G:\study\php\parallel\a.php');
$a=5;
$future1=$r1->run(function ()use ($a){//线程1
sleep(1);
echo "this is thread1 start\n\r";
$a++;
echo "thread1 a is $a\n\r";
sleep(5);
echo "this is thread1 end\n\r";
return 1;
});
$future2=$r2->run(function ($p1){//线程2
echo "this is thread2 start\n\r";
sleep(5);
echo "thread2 a is $p1\n\r";
echo "this is thread2 end\n\r";
return 2;
},[$a]);//外部变量也可以通过第二个参数传入线程
$future3=$r2->run(function (){//线程3
echo "this is thread3 start\n\r";
sleep(5);
echo "this is thread3 end\n\r";
return 3;
});
echo "主线程开始\n\r";
echo "future1的值是:".$future1->value()."\n\r";
echo "future2的值是:".$future2->value()."\n\r";
echo "future3的值是:".$future3->value()."\n\r";
几个要点
1.同一个运行对象运行线程是单线程按顺序执行的,不同的运行对象运行线程是并发的。
2.线程与线程之间不能共享内存,php本身也不支持(TSRM),线程通信只能使用channel(下文会讲)。
3.future是run的返回的对象,future->value()可以获取线程闭包里返回的值,也就意味着程序运行到此处时该线程必然已经结束,所以可以通过多个future->value()实现等待多个线程完成的功能
channel
线程通信只能使用 channel,使用方法与golang一样,参数为容量,send时channel已满时线程堵塞,recv时channel为空时线程堵塞。可以传闭包!
$r1=new \parallel\Runtime('G:\study\php\parallel\a.php');
$r2=new \parallel\Runtime('G:\study\php\parallel\a.php');
$c=new \parallel\Channel(2);
$r1->run(function ()use($c){
while (1){
echo "开始获取...\n\r";
$a=$c->recv();
if($a instanceof Closure){
$a();
}else{
print_r($a);
echo "\n\r";
}
}
});
$r2->run(function ()use($c){
$c->send(function (){
echo "我是闭包\n\r";
});
sleep(5);
$c->send([1,2,3]);
});
以上是几个核心api,其他可查阅官网,有时间再深入学习一下。
评价
不能共享内存,代码,与其他语言多线程相比局限性非常大,如果不是有个chanel实际跟多进程也没多大区别。相对于多进程,线程控制因为有chanel要易用一点…