默认分类

PHP多线程模块pthreads的使用

最近开发一个项目,需要在一个周期内执行许多个类似的任务。

印象中的PHP无法异步执行代码,所以计划使用PHP格式化MySQL的数据,然后提交给Bash Shell Script处理,毕竟在Bash Shell下,可以利用许多GNU程序的组合来实现我的需求,更重要的是在命令末尾加一个”&”符号,即可把任务丢到后台执行,立刻开始下一个任务,最后一切就绪后再提交结果给PHP收尾。

不得不说这是一个很糟糕的方案,虽然数据经过PHP初步格式化,但Shell Script仍然要使用一部分文字处理工具处理数据,其中可能因为某个字段数据比较特殊而出错,由于执行任务需要调用多个程序,效率低下,部分程序之间要使用管道,这些都增加了大量的服务器CPU以及物理内存资源的消耗,更烦的是要循环查询是否所有线程都已经结束工作……

为了让任务能高效率完成,于是寻找了一下有关PHP多线程的解决方案,发现原来PHP有一个提供多线程功能的模块——pthreads。

PHP官方对pthreads模块的介绍:

pthreads is an Object Orientated API that allows user-land multi-threading in PHP. It includes all the tools you need to create multi-threaded applications. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.

介绍说pthreads模块提供了所有构建多线程PHP应用程序所需的工具,果然是世界上最好的语言。

根据PHP官方的文档,使用pthreads模块,需要开启线程安全功能,也就是编译PHP的时候,必须加上参数–enable-maintainer-zts。

此外,开启pthreads模块后,无法使用CGI模式运行PHP。

从PECL可以取得pthreads源码,继而进行编译安装,如果安装了php pear,还可以通过pecl命令安装:

pecl install pthreads

下面说说pthreads模块的使用。

这是pthreads模块提供的Thread类的概要:

Thread extends Threaded implements Countable , Traversable , ArrayAccess {
/* 方法 */
public void detach ( void )
public integer getCreatorId ( void )
public static Thread getCurrentThread ( void )
public static integer getCurrentThreadId ( void )
public integer getThreadId ( void )
public static mixed globally ( void )
public boolean isJoined ( void )
public boolean isStarted ( void )
public boolean join ( void )
public void kill ( void )
public boolean start ([ integer $options ] )
/* 继承的方法 */
public array Threaded::chunk ( integer $size , boolean $preserve )
public integer Threaded::count ( void )
public bool Threaded::extend ( string $class )
public Threaded Threaded::from ( Closure $run [, Closure $construct [, array $args ]] )
public array Threaded::getTerminationInfo ( void )
public boolean Threaded::isRunning ( void )
public boolean Threaded::isTerminated ( void )
public boolean Threaded::isWaiting ( void )
public boolean Threaded::lock ( void )
public boolean Threaded::merge ( mixed $from [, bool $overwrite ] )
public boolean Threaded::notify ( void )
public boolean Threaded::pop ( void )
public void Threaded::run ( void )
public mixed Threaded::shift ( void )
public mixed Threaded::synchronized ( Closure $block [, mixed $... ] )
public boolean Threaded::unlock ( void )
public boolean Threaded::wait ([ integer $timeout ] )
}

可以看到Thread是继承了Threaded类,因此我们要使用多线程功能时,直接需要创建一个继承于Thread的类即可:

<?php
class myclass extends Thread
{
	// Here gose the code
}

其中run()方法与start()方法是关键。

在需要创建线程执行任务时,调用的是start()方法,而start()又会调用run()方法。

例:

<?php
class myclass extends Thread
{
    // Start方法所执行的方法
    public function run() {
	echo rand()."\n";
    }
}

$myobj = new myclass(); // 创建一个名为myobj的对象
$myobj->start(); // 调用myobj对象的start()方法,start()方法会调用run()方法

上面的代码,会另起一个线程,输出一个随机数字。

如果我要在十秒后才输出这个随机数字,而且要输出100次,传统来说,至少需要1000秒才能完成输出任务,但使用线程,可以让所有输出几乎同时在十秒完成。

例:

<?php
class myclass extends Thread
{
    // Start方法所执行的方法
    public function run() {
	sleep(10); // 延迟十秒
	echo rand()."\n";
    }
}
for ($i = 0; $i < 100; $i++) {
$myobj[$i] = new myclass(); // 创建一个名为myobj的对象
$myobj[$i]->start(); // 调用myobj对象的start()方法,start()方法会调用run()方法
}

上面的代码,使用了数组,每个数组元素都是一个myclass类的对象,这些对象会同时(虽然创建对象,开始线程等操作也需要时间,但时间非常短,可以忽略)创建一百个线程,这一百个线程同时开始十秒的延迟,十秒后同时输出一个数字:

Pthreads

由于使用的是线程模式,创建一个PHP进程即可处理所有线程,现在无需额外格式化数据,使用PHP的函数实现了所需的功能,相比之前不仅多Bash进程,还多执行各种杂七杂八程序的方案,任务执行效率大大提高。

No Comments

101 Posts

自信、努力、活出精彩;以前未所见的颜色,绘大千世界!
View all posts

Leave a reply

Your email address will not be published. Required fields are marked *