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. 对于分类问题的神经网络最后一层的函数:sigmoid、softmax与损失函数

    对于分类问题的神经网络最后一层的函数做如下知识点总结: sigmoid和softmax一般用作神经网络的最后一层做分类函数(备注:sigmoid也用作中间层做激活函数): 对于类别数量大于2的分类问题 ...

  2. more 可翻页查看(一页一页翻动)

    命令解释 我们查看数据的时候,使用前面提到的nl与cat.tac等等,都是将文件内容一次性输出到屏幕上,看起来不是很方便,那我们就可以使用这个命令,一页一页查看,前面的数据不至于看不到. 命令说明 [ ...

  3. 本地管理表空间和字典管理表空间的特点,ASSM有什么特点

    字典管理表空间(Dictionary-Managed Tablespace简称DMT),8i以前包括以后都还可以使用的一种表空间管理模式,通过数据字典管理表空间的空间使用. Oracle使用两个字典来 ...

  4. Hadoop2.0构成之YARN

    YARN产生背景 Hadoop1.x中的MapReduce构成图如下: 在Hadoop1.x中MapReduce是Master/Slave结构,在集群中的表现形式为:1个JobTracker带多个Ta ...

  5. 了解java的类加载器

    1.java运行之前,编译后的class文件需要加载到虚拟机内存,这必须用到class的加载器来加载,所以有必要了解加载器原理. 2.加载器采用父类委派机制加载,这样的目的是保证基础类仅仅加载一次(比 ...

  6. Bogart gSub.vb

    '--------------Job No 0900408 -------------- '--DIM PART ONE ONLINE Update Order Qty '''主要新加過程名 Refr ...

  7. RouterOS 5.16软路由安装图解教程

    说明:RouterOS是一种路由器操作系统,它可以安装到普通的个人电脑上面,替代硬件路由器 RouterOS版本:RouterOS 5.16 硬件要求: 1.支持多核CPU 2.内存最大支持到2G 3 ...

  8. WPF 自定义属性

    做了一个自定义控件和一个自定义Grid,里面的元素可以随着绑定属性变化: 效果图(一定滑块): 关键代码: 1.自定义属性代码: public class MyGrid : Grid { public ...

  9. WebService客户端调用的几种方式

    1.用组件HTTPRIO,支持VCL WIN32和FIRE MONKEY跨平台Android手机 HTTPRIO1.URL := 'http://127.0.0.1:8080/soap/IsoapTe ...

  10. 列表(ul ol dl)

    Title 1 2 3 1 2 3 a 1 2 b 1 2 <!DOCTYPE html> <html lang="en"> <head> &l ...