Pool对象是多个Worker对象的容器,同时也是它们的控制器,对Worker功能更高抽象。

比如Worker是河,而线程是运行在河里的船。Pool则是管理着多条河。
<?php
//继承Collectable垃圾收集类,好让Pool::collect进行收集
class Sql extends Collectable {
private $sql = '';
private $data = array(); public function __construct($sql) {
$this->sql = $sql;
} public function run() {
$db = $this->worker->getDb();
$res = mysql_query($this->sql, $db);
$tmp = array();
while($row = mysql_fetch_assoc($res)) {
//这里不能使用$this->data[] = $row;这种方式。
$tmp[] = $row;
}
$this->data = $tmp;
//这里工作完后,设置为垃圾
//在Pool::collect中isGarbage()判断时则为真
$this->setGarbage();
} public function getData() {
return $this->data;
}
} class SqlWorker extends Worker {
protected static $db = null; public function getDb() {
if(!self::$db) {
self::$db = mysql_connect('127.0.0.1', 'root', '');
mysql_select_db('test', self::$db);
}
return self::$db;
}
} //这里创建5个Worker对象的Pool线程池
$pool = new Pool(5, 'SqlWorker'); //我们创建20个Sql线程对象,并提交到Pool的Worker中
$sqls = array();
for($ix = 0; $ix < 20; ++$ix) {
$sql = new Sql("select * from test order by id limit {$ix},1");
$sqls[] = $sql; //$pool->submit($sql);不要在这里submit
} //注意,这里循环提交$sql
//如果把$pool->submit放到前面的for循环内,会出现一个错误
//第一个Sql对象的sql语句会跟最后一个相同,导致结果出现问题
foreach($sqls as $sql) {
//这里的submit方法有问题,它会修改$sqls
//导致第一个Sql对象与最后一个相同
//不知是不是BUG
$pool->submit($sql);
} //等待队列中执行完成
$pool->shutdown(); $ret = array();
foreach($sqls as $sql) {
$ret[] = $sql->getData();
}
file_put_contents('ret.txt', var_export($ret, true)); //回收已完成的对象
$pool->collect(function($sql){
return $sql->isGarbage();
});
array (
0 =>
array (
0 =>
array (
'id' => '20',
'name' => 'mmm',
),
),
1 =>
array (
0 =>
array (
'id' => '2',
'name' => '222',
),
),
2 =>
array (
0 =>
array (
'id' => '3',
'name' => '333',
),
),
3 =>
array (
0 =>
array (
'id' => '4',
'name' => '444',
),
),
4 =>
array (
0 =>
array (
'id' => '5',
'name' => '555',
),
),
5 =>
array (
0 =>
array (
'id' => '6',
'name' => '666',
),
),
6 =>
array (
0 =>
array (
'id' => '7',
'name' => '777',
),
),
7 =>
array (
0 =>
array (
'id' => '8',
'name' => '888',
),
),
8 =>
array (
0 =>
array (
'id' => '9',
'name' => '999',
),
),
9 =>
array (
0 =>
array (
'id' => '10',
'name' => 'aaa',
),
),
10 =>
array (
0 =>
array (
'id' => '11',
'name' => 'bbb',
),
),
11 =>
array (
0 =>
array (
'id' => '12',
'name' => 'ccc',
),
),
12 =>
array (
0 =>
array (
'id' => '13',
'name' => 'ddd',
),
),
13 =>
array (
0 =>
array (
'id' => '14',
'name' => 'eee',
),
),
14 =>
array (
0 =>
array (
'id' => '15',
'name' => 'fff',
),
),
15 =>
array (
0 =>
array (
'id' => '16',
'name' => 'ggg',
),
),
16 =>
array (
0 =>
array (
'id' => '17',
'name' => 'vvv',
),
),
17 =>
array (
0 =>
array (
'id' => '18',
'name' => 'hhh',
),
),
18 =>
array (
0 =>
array (
'id' => '19',
'name' => 'nnn',
),
),
19 =>
array (
0 =>
array (
'id' => '20',
'name' => 'mmm',
),
),
)

从结果可以看出,第一条记录跟最后一条是相同的,再没有pool->submit之前$sqls数组中的对象都是正确的,submit之后第一个对象的数据就改变了,不知道是不是pthreads的BUG。

 
上述代码我们通过创建一个包含5个SqlWorker对象的pool,然后创建20个Sql对象加入到pool中。
 
当然我们的Sql类并不一定非要继承自Collectable类,我们也可自定义判断什么时候可回收。
<?php
//继承Threaded类,Threaded提供了隐式的线程安全机制
//这个对象中的所有操作都是线程安全的
class MyWork extends Threaded {
private $name = '';
private $do = false;
private $data = ''; public function __construct($name) {
$this->name = $name;
} public function run() {
$this->data = "{$this->name} run... in thread [" . $this->worker->getName() . "] \r\n";
//通过do来判断是否完成
//如果为true,则让Pool::collect回收
$this->do = true;
} public function isDo() {
return $this->do;
} public function getData() {
return $this->data;
}
} class MyWorker extends Worker {
public static $name = 0; public function __construct() {
self::$name++;
} public function run() { } public function getName() {
return self::$name;
}
} $pool = new Pool(5, 'MyWorker'); $works = array();
for($ix = 0; $ix < 20; ++$ix) {
$work = new MyWork($ix);
$works[] = $work;
} foreach($works as $work) {
$pool->submit($work);
}
$pool->shutdown(); foreach($works as $work) {
echo $work->getData();
} //回收已完成的对象
$pool->collect(function($work){
//我们通过自定义函数isDo来判断对象是否执行完毕
return $work->isDo();
});
执行结果如下:
19 run... in thread [5]
1 run... in thread [2]
2 run... in thread [3]
3 run... in thread [4]
4 run... in thread [5]
5 run... in thread [1]
6 run... in thread [2]
7 run... in thread [3]
8 run... in thread [4]
9 run... in thread [5]
10 run... in thread [1]
11 run... in thread [2]
12 run... in thread [3]
13 run... in thread [4]
14 run... in thread [5]
15 run... in thread [1]
16 run... in thread [2]
17 run... in thread [3]
18 run... in thread [4]
19 run... in thread [5]

第一条记录为什么会有问题,前面我已经说过了。这里我们看20个MyWork对象,它们顺序的加入到5个MyWorker对象中,如果第一条记录没有问题的话,它们分别加入到1,2,3,4,5的MyWorker中,然后远行run方法。

 
 
 

php Pthread 多线程 (六) Pool类 线程池的更多相关文章

  1. 多线程(七)JDK原生线程池

    如同数据库连接一样,线程的创建.切换和销毁同样会耗费大量的系统资源.为了复用创建好的线程,减少频繁创建线程的次数,提高线程利用率可以引用线程池技术.使用线程池的优势有如下几点:        1.保持 ...

  2. C#多线程之旅(3)——线程池

    v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...

  3. C# 多线程的自动管理(线程池) 基于Task的方式

    C# 多线程的自动管理(线程池) 在多线程的程序中,经常会出现两种情况:    1. 应用程序中线程把大部分的时间花费在等待状态,等待某个事件发生,然后给予响应.这一般使用 ThreadPool(线程 ...

  4. 第十章:Python高级编程-多线程、多进程和线程池编程

    第十章:Python高级编程-多线程.多进程和线程池编程 Python3高级核心技术97讲 笔记 目录 第十章:Python高级编程-多线程.多进程和线程池编程 10.1 Python中的GIL 10 ...

  5. Android 多线程: 完全解析线程池ThreadPool原理&使用

    目录 1. 简介 2. 工作原理 2.1 核心参数 线程池中有6个核心参数,具体如下 上述6个参数的配置 决定了 线程池的功能,具体设置时机 = 创建 线程池类对象时 传入 ThreadPoolExe ...

  6. java核心-多线程(6)-线程池-ThreadPoolExecutor

    1.java多线程编程少不了使用线程池,线程池相关的工具类所在jdk包,java.util.concurrent 2.使用示例 demo1 public class ThreadPoolDemo { ...

  7. juc线程池原理(六):jdk线程池中的设计模式

    一.jdk中默认线程池中的代理模式 单例类线程池只有一个线程,无边界队列,适合cpu密集的运算.jdk中创建线程池是通过Executors类中提供的静态的方法来创建的,其中的单例类线程池的方法如下: ...

  8. ThreadPool类(线程池)

    原文:ThreadPool类(线程池) CLR线程池并不会在CLR初始化时立即建立线程,而是在应用程序要创建线程来运行任务时,线程池才初始化一个线程.线程池初始化时是没有线程的,线程池里的线程的初始化 ...

  9. Java线程池的原理及几类线程池的介绍

    刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...

随机推荐

  1. CRM 2016 级联过滤 类比省市县

    以下以省市为例: function preFilterLookup() { //要进行过滤的lookup按钮加入addPresearch事件 Xrm.Page.getControl("shi ...

  2. 递归神经网络(Recursive Neural Network, RNN)

    信息往往还存在着诸如树结构.图结构等更复杂的结构.这就需要用到递归神经网络 (Recursive Neural Network, RNN),巧合的是递归神经网络的缩写和循环神经网络一样,也是RNN,递 ...

  3. ubuntu 18.04下svn的安装与基本命令

    一.安装: apt-get install subversion 二.基本命令 1.将文件checkout到本地目录 svn checkout path(path是服务器 上的目录)例如:svn ch ...

  4. 微软SMB 3.0文件共享协议新特性介绍

    SMB(*nix平台和Win NT4.0又称CIFS)协议是Windows平台标准文件共享协议.Linux平台通过samba来支持.SMB最新版本v3.0,在v2.0基础上针对WAN和分布式有改进.详 ...

  5. 《GPU高性能编程CUDA实战》附录三 关于book.h

    ▶ 本书中用到的公用函数放到了头文件book.h中 #ifndef __BOOK_H__ #define __BOOK_H__ #include <stdio.h> #include &l ...

  6. Hive启动异常

    [root@host ~]# hivewhich: no hbase in (/root/app/apache-maven-3.5.2/bin:/usr/local/sbin:/usr/local/b ...

  7. 57. 激活office时出下以下问题的解决方案

      我们拿出一段来分析一下(我所知道的不多)SKU ID:1b686580-9fb1-4b88-bfba-eae7c0da31adLICENSE NAME: Office 15, OfficeProP ...

  8. tab form

    procedure TForm2.ToolButton1Click(Sender: TObject); var frm: TForm; begin frm := TForm.Create(Applic ...

  9. style css

    Title 语文 用户名 用户名 数学 英语 <!DOCTYPE html><html lang="en"><head> <meta ch ...

  10. UI5-文档-4.17-Fragment Callbacks

    现在我们已经集成了对话框,是时候添加一些用户交互了.用户肯定希望在某个时候再次关闭对话框,因此我们添加一个按钮来关闭对话框并分配一个事件处理程序. Preview The dialog now has ...