新线程扩展,它使类,函数甚至整个文件都可以被线程化;需要PHP的ZTS版本,目前仅可使用于7.2;不应在Web服务器环境中使用。应仅限于基于CLI的应用程序
pht采取的线程化方法
- pht采用的线程处理方法是将线程本身抽象到专用对象后面。然后将任务添加到线程的内部任务队列中,在线程启动时处理它们。
- 所有线程任务将在新产生的线程内部独立执行,对于类任务,这意味着无法在线程之间传递生成的对象。通过使线程上下文彼此完全分开;就不需要序列化线程对象的属性
- pht\HashTable,pht\Vector和pht\Queue数据结构允许线程之间采用双向通信方式,它们公开互斥锁以控制其完整性。这些数据结构可以在线程之间安全地传递,并由多个线程使用与它们一起打包的互斥锁进行操作,它们是跨线程引用计数的,因此不需要显式销毁它们。这种线程化方法意味着仅需要在线程之间安全地传递给定的内置数据结构。
扩展地址
windows:https://github.com/tpunt/pht/releases
源码:https://github.com/tpunt/pht
pht\Thread类
提取出一个本地线程。它有一个内部任务队列,可以通过方法将新任务推送到此队列中。
构造线程队列
$thread = new pht\Thread();
// 将新的类名$className(此类必须实现pht\Runnable接口)添加到pht\Thread的内部任务队列中;参数$ctorArgs为类$className的构造函数参数(这些参数将被序列化传给另一个线程),线程启动时将执行类的run方法
$thread->addClassTask($className, ...$ctorArgs);
// 将新的文件名$fileName添加到pht\Thread的内部任务队列中;参数$globals将放在超全局变量$_THREAD中,在文件$fileName中可直接使用(这些参数将被序列化传给另一个线程)
$thread->addFileTask($fileName, ...$globals);
// 将新的回调函数$func添加到pht\Thread的内部任务队列中;参数$funcArgs为函数$func的参数(这些参数将被序列化传给另一个线程)
$thread->addFunctionTask($func, ...$funcArgs);
启动线程
// 启动线程开始处理内部任务队列
$thread->start();
// 在start方法后使用,防止出现未定义的行为
$thread->join();
// 获取线程当前的任务数
$thread->taskCount();
pht\HashTable类
- 线程间通信(ITC)的数据结构,可以在线程之间安全地传递,并可以使用数据结构中随附的互斥锁由多个线程进行操作
- 它是跨线程引用计数的,因此不需要显式销毁它
- 允许对其对象进行数组访问
$hashTable = new pht\HashTable;
// 通过数组形式设置数据以在其他线程中使用
$hashTable['keys'] = 'values';
// 获取哈希表当前大小,被多个线程使用需要持有pht\HashTable的互斥锁
$hashTable->size();
// 获取与哈希表关联的互斥锁,通过同一线程重新获取已经获得的互斥锁将导致死锁
$hashTable->lock();
// 释放释放与哈希表关联的互斥锁。
$hashTable->unlock();
pht\Vector类
- 线程间通信(ITC)数据结构。可以在线程之间安全地传递,并由多个线程使用与数据结构打包在一起的互斥锁进行操作。
- 它是跨线程引用计数的,因此不需要显式地销毁。
- 允许对其对象进行数组访问。
创建向量
// 创建一个$size大小的向量,想两种空白插槽的初始化值为$value(类型不限)
$vector = new pht\Vector($size = 0, $value = 0);
// 调整向量大小为$size,向量中新增空白插槽的初始化值为$value(类型不限),如果$size减小,向量将被截断
$vector->resize($size, $value = 0);
向量更新值
// 向量中的值将被,将被序列化,因为它可能在线程之间传递
// 向量中值超过初始化时指定的大小,向量将自动扩建
// 在向量的指定位置$offset插入值$value
$vector->insertAt($value, $offset);
// 在向量结尾处插入值值$value
$vector->push($value);
// 在向量开始处插入值值$value
$vector->unshift($value);
// 将向量的指定位置$offset的值更新为$value,更新不存在位置的值将导致错误异常
$vector->updateAt($value, $offset);
// 在向量的指定位置$offset的值删除,删除不存在位置的值将导致错误异常
$vector->deleteAt($value, $offset);
获取向量值
// 获取向量末尾的值,向量中无数据时将导致错误异常
$vector->pop();
// 获取向量开始的值,向量中无数据时将导致错误异常
$vector->shift();
向量互斥锁
// 获取与向量关联的互斥锁,通过同一线程重新获取已经获得的互斥锁将导致死锁
$vector->lock();
// 释放与向量关联的互斥锁
$vector->unlock();
获取向量大小
// 获取向量当前大小,被多个线程使用需要持有pht\Vector的互斥锁
$vector->size();
pht\Queue类
- 线程间通信(ITC)数据结构。可以在线程之间安全地传递,并由多个线程使用与数据结构打包在一起的互斥锁进行操作。
- 它是跨线程引用计数的,因此不需要显式地销毁它。
- pht\Queue中的所有值均已序列化,因此从队列中提取值将要求对其进行反序列化。
- 如果在循环内执行队列前端值的检查,则可能会导致明显的性能下降。
队列使用
$queue = new pht\Queue();
// 将值$value推入队列末尾
$queue->push($value);
// 获取队列最前面的值并删除
$queue->front();
// 获取队列末尾的值并删除
$queue->pop();
队列互斥锁
// 获取与队列关联的互斥锁,通过同一线程重新获取已经获得的互斥锁将导致死锁
$queue->lock();
// 释放与队列关联的互斥锁
$queue->unlock();
队列大小
// 获取队列当前大小,被多个线程使用需要持有pht\Queue的互斥锁
$queue->size();
pht\AtomicInteger类
- 原子值。
- 它允许一个整数在多个线程之间安全地传递和操作。
- 这个类公开的方法不需要互斥锁,因为它们将隐式获得内部互斥锁。
- 当涉及同一个pht\AtomicInteger对象的多个操作需要被分组在一起时。原子值的互斥锁是可重入安全的。
原子整数使用
// 创建原子整数,初始值为$value
$atomicInteger = new pht\AtomicInteger($value = 0);
// 将原子整数的值设置为$value
$atomicInteger->set($value);
// 将原子整数的值加1
$atomicInteger->inc();
// 将原子整数的值减1
$atomicInteger->dec();
// 获取原子整数的值
$atomicInteger->get();
原子整数互斥锁
// 获取与原子整数关联的互斥锁,原子值的互斥锁是可重入安全的。对于同一个线程来说,重新获取已经获得的互斥锁是有效的。
// 互斥锁只在需要将多个操作组合在一起时才需要获取
$atomicInteger->lock();
// 释放与原子整数关联的互斥锁
$atomicInteger->unlock();