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. 使用V$SQL_PLAN视图获取曾经执行过的SQL语句执行计划

    通常我们查看SQL语句的执行计划都是通过EXPLAIN PLAN或者AUTOTRACE来完成.但是这些查看方法有一个限制,它们都是人为触发而产生的,无法获得数据库系统中曾经执行过的SQL语句执行计划. ...

  2. Spark standalone运行模式

    Spark Standalone 部署配置 Standalone架构 手工启动一个Spark集群 https://spark.apache.org/docs/latest/spark-standalo ...

  3. CentOS重新加载网卡报错 Active connection path: /org/freedesktop/NetworkManager/ActiveConnection/

    重新加载网卡时出现的错误如下: 1 [root@vdb1 dev]# service network restart 2 Shutting down interface eth0: Device st ...

  4. mybatis Dynamic SQL动态 SQL

    动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空格 ...

  5. HTML|CSS之CSS选择器及样式

    知识内容: 1.CSS选择器 2.CSS常用样式 参考:http://www.cnblogs.com/yuanchenqi/articles/5977825.html 一.CSS选择器 1.基础选择器 ...

  6. QT按键(Qbutton)改变颜色

    第一种是按键上面的字颜色的改变:   ui->motor1->setStyleSheet("color: red"); 效果: 第二种是背景改变: ui->mot ...

  7. linux更换shell外壳zsh

    linux-外壳内核与shell的关系 内核处于外壳之中,通过外壳与shell(命令行)交互 外壳可以更换 ############################################## ...

  8. left join 如何增加where条件(在on的后面),这很重要

    SELECT [学号], [姓名],[备注2],[年级],专业,[学院],[x30] FROM [总表] left join k指标体系  on  学号 = x01 where 年级='2014'

  9. leetcode961

    class Solution: def repeatedNTimes(self, A): doubleN = len(A) N = doubleN / 2 dic = {} for a in A: i ...

  10. 1.Redis的应用场景

    转自:http://www.runoob.com/redis/redis-tutorial.html Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在 ...