当前位置:首页 > PHP教程 > php高级应用 > 列表

php pthreads多线程的安装与使用

发布:smiling 来源: PHP粉丝网  添加日期:2021-07-06 10:35:06 浏览: 评论:0 

安装Pthreads 基本上需要重新编译PHP,加上 --enable-maintainer-zts 参数,但是用这个文档很少;bug会很多很有很多意想不到的问题,生成环境上只能呵呵了,所以这个东西玩玩就算了,真正多线程还是用Python、C等等

一、安装

这里使用的是 php-7.0.2

  1. ./configure \ 
  2. --prefix=/usr/local/php7 \ 
  3. --with-config-file-path=/etc \ 
  4. --with-config-file-scan-dir=/etc/php.d \ 
  5. --enable-debug \ 
  6. --enable-maintainer-zts \ 
  7. --enable-pcntl \ 
  8. --enable-fpm \ 
  9. --enable-opcache \ 
  10. --enable-embed=shared \ 
  11. --enable-json=shared \ 
  12. --enable-phpdbg \ 
  13. --with-curl=shared \ 
  14. --with-mysql=/usr/local/mysql \ 
  15. --with-mysqli=/usr/local/mysql/bin/mysql_config \ 
  16. --with-pdo-mysql 
  17. make && make install 

安装pthreads

pecl install pthreads

二、Thread

  1. <?php 
  2. #1 
  3. $thread = new class extends Thread { 
  4. public function run() { 
  5. echo "Hello World {$this->getThreadId()}\n";  
  6. }  
  7. }; 
  8. $thread->start() && $thread->join(); 
  9. #2 
  10. class workerThread extends Thread {  
  11. public function __construct($i){ 
  12. $this->i=$i
  13. public function run(){ 
  14. while(true){ 
  15. echo $this->i."\n"
  16. sleep(1); 
  17. }  
  18. }  
  19. for($i=0;$i<50;$i++){ 
  20. $workers[$i]=new workerThread($i); 
  21. $workers[$i]->start(); 
  22. ?> 

三、 Worker 与 Stackable

Stackables are tasks that are executed by Worker threads. You can synchronize with, read, and write Stackable objects before, after and during their execution.

  1. <?php 
  2. class SQLQuery extends Stackable { 
  3. public function __construct($sql) { 
  4. $this->sql = $sql
  5. public function run() { 
  6. $dbh = $this->worker->getConnection(); 
  7. $row = $dbh->query($this->sql); 
  8. while($member = $row->fetch(PDO::FETCH_ASSOC)){ 
  9. print_r($member); 
  10. class ExampleWorker extends Worker { 
  11. public static $dbh
  12. public function __construct($name) { 
  13. public function run(){ 
  14. self::$dbh = new PDO('mysql:host=10.0.0.30;dbname=testdb','root','123456'); 
  15. public function getConnection(){ 
  16. return self::$dbh
  17. $worker = new ExampleWorker("My Worker Thread"); 
  18. $sql1 = new SQLQuery('select * from test order by id desc limit 1,5'); 
  19. $worker->stack($sql1); 
  20. $sql2 = new SQLQuery('select * from test order by id desc limit 5,5'); 
  21. $worker->stack($sql2); 
  22. $worker->start(); 
  23. $worker->shutdown(); 
  24. ?> 

四、 互斥锁

什么情况下会用到互斥锁?在你需要控制多个线程同一时刻只能有一个线程工作的情况下可以使用,一个简单的计数器程序,说明有无互斥锁情况下的不同

  1. <?php 
  2. $counter = 0; 
  3. $handle=fopen("/tmp/counter.txt""w"); 
  4. fwrite($handle$counter ); 
  5. fclose($handle); 
  6. class CounterThread extends Thread { 
  7. public function __construct($mutex = null){ 
  8. $this->mutex = $mutex
  9. $this->handle = fopen("/tmp/counter.txt""w+"); 
  10. public function __destruct(){ 
  11. fclose($this->handle); 
  12. public function run() { 
  13. if($this->mutex) 
  14. $locked=Mutex::lock($this->mutex); 
  15. $counter = intval(fgets($this->handle)); 
  16. $counter++; 
  17. rewind($this->handle); 
  18. fputs($this->handle, $counter ); 
  19. printf("Thread #%lu says: %s\n"$this->getThreadId(),$counter); 
  20. if($this->mutex) 
  21. Mutex::unlock($this->mutex); 
  22. //没有互斥锁 
  23. for ($i=0;$i<50;$i++){ 
  24. $threads[$i] = new CounterThread(); 
  25. $threads[$i]->start(); 
  26. //加入互斥锁 
  27. $mutex = Mutex::create(true); 
  28. for ($i=0;$i<50;$i++){ 
  29. $threads[$i] = new CounterThread($mutex); 
  30. $threads[$i]->start(); 
  31. Mutex::unlock($mutex); 
  32. for ($i=0;$i<50;$i++){ 
  33. $threads[$i]->join(); 
  34. Mutex::destroy($mutex); 
  35. ?> 

多线程与共享内存

在共享内存的例子中,没有使用任何锁,仍然可能正常工作,可能工作内存操作本身具备锁的功能。

  1. <?php 
  2. $tmp = tempnam(__FILE__'PHP'); 
  3. $key = ftok($tmp'a'); 
  4. $shmid = shm_attach($key); 
  5. $counter = 0; 
  6. shm_put_var( $shmid, 1, $counter ); 
  7. class CounterThread extends Thread { 
  8. public function __construct($shmid){ 
  9. $this->shmid = $shmid
  10. public function run() { 
  11. $counter = shm_get_var( $this->shmid, 1 ); 
  12. $counter++; 
  13. shm_put_var( $this->shmid, 1, $counter ); 
  14. printf("Thread #%lu says: %s\n"$this->getThreadId(),$counter); 
  15. for ($i=0;$i<100;$i++){ 
  16. $threads[] = new CounterThread($shmid); 
  17. for ($i=0;$i<100;$i++){ 
  18. $threads[$i]->start(); 
  19. for ($i=0;$i<100;$i++){ 
  20. $threads[$i]->join(); 
  21. shm_remove( $shmid ); 
  22. shm_detach( $shmid ); 
  23. ?> 

五、 线程同步

有些场景我们不希望 thread->start() 就开始运行程序,而是希望线程等待我们的命令。thread−>wait();测作用是thread−>start()后线程并不会立即运行,只有收到 thread->notify(); 发出的信号后才运行

  1. <?php 
  2. $tmp = tempnam(__FILE__'PHP'); 
  3. $key = ftok($tmp'a'); 
  4. $shmid = shm_attach($key); 
  5. $counter = 0; 
  6. shm_put_var( $shmid, 1, $counter ); 
  7. class CounterThread extends Thread { 
  8. public function __construct($shmid){ 
  9. $this->shmid = $shmid
  10. public function run() { 
  11. $this->synchronized(function($thread){ 
  12. $thread->wait(); 
  13. }, $this); 
  14. $counter = shm_get_var( $this->shmid, 1 ); 
  15. $counter++; 
  16. shm_put_var( $this->shmid, 1, $counter ); 
  17. printf("Thread #%lu says: %s\n"$this->getThreadId(),$counter); 
  18. for ($i=0;$i<100;$i++){ 
  19. $threads[] = new CounterThread($shmid); 
  20. for ($i=0;$i<100;$i++){ 
  21. $threads[$i]->start(); 
  22. for ($i=0;$i<100;$i++){ 
  23. $threads[$i]->synchronized(function($thread){ 
  24. $thread->notify(); 
  25. }, $threads[$i]); 
  26. for ($i=0;$i<100;$i++){ 
  27. $threads[$i]->join(); 
  28. shm_remove( $shmid ); 
  29. shm_detach( $shmid ); 
  30. ?> 

六、线程池

一个Pool类

  1. <?php 
  2. class Update extends Thread { 
  3. public $running = false; 
  4. public $row = array(); 
  5. public function __construct($row) { 
  6. $this->row = $row
  7. $this->sql = null; 
  8. public function run() { 
  9. if(strlen($this->row['bankno']) > 100 ){ 
  10. $bankno = safenet_decrypt($this->row['bankno']); 
  11. }else
  12. $error = sprintf("%s, %s\r\n",$this->row['id'], $this->row['bankno']); 
  13. file_put_contents("bankno_error.log"$error, FILE_APPEND); 
  14. ifstrlen($bankno) > 7 ){ 
  15. $sql = sprintf("update members set bankno = '%s' where id = '%s';"$bankno$this->row['id']); 
  16. $this->sql = $sql
  17. printf("%s\n",$this->sql); 
  18. class Pool { 
  19. public $pool = array(); 
  20. public function __construct($count) { 
  21. $this->count = $count
  22. public function push($row){ 
  23. if(count($this->pool) < $this->count){ 
  24. $this->pool[] = new Update($row); 
  25. return true; 
  26. }else
  27. return false; 
  28. public function start(){ 
  29. foreach ( $this->pool as $id => $worker){ 
  30. $this->pool[$id]->start(); 
  31. public function join(){ 
  32. foreach ( $this->pool as $id => $worker){ 
  33. $this->pool[$id]->join(); 
  34. public function clean(){ 
  35. foreach ( $this->pool as $id => $worker){ 
  36. if(! $worker->isRunning()){ 
  37. unset($this->pool[$id]); 
  38. try { 
  39. $dbh = new PDO("mysql:host=" . str_replace(':'';port='$dbhost) . ";dbname=$dbname"$dbuser$dbpwarray
  40. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
  41. PDO::MYSQL_ATTR_COMPRESS => true 
  42. ); 
  43. $sql = "select id,bankno from members order by id desc"
  44. $row = $dbh->query($sql); 
  45. $pool = new Pool(5); 
  46. while($member = $row->fetch(PDO::FETCH_ASSOC)) 
  47. while(true){ 
  48. if($pool->push($member)){ //压入任务到池中 
  49. break
  50. }else//如果池已经满,就开始启动线程 
  51. $pool->start(); 
  52. $pool->join(); 
  53. $pool->clean(); 
  54. $pool->start(); 
  55. $pool->join(); 
  56. $dbh = null; 
  57. } catch (Exception $e) { 
  58. echo '[' , date('H:i:s') , ']''系统错误'$e->getMessage(), "\n"
  59. ?> 

动态队列线程池

上面的例子是当线程池满后执行start统一启动,下面的例子是只要线程池中有空闲便立即创建新线程。

  1. <?php 
  2. class Update extends Thread { 
  3. public $running = false; 
  4. public $row = array(); 
  5. public function __construct($row) { 
  6. $this->row = $row
  7. $this->sql = null; 
  8. //print_r($this->row); 
  9. public function run() { 
  10. if(strlen($this->row['bankno']) > 100 ){ 
  11. $bankno = safenet_decrypt($this->row['bankno']); 
  12. }else
  13. $error = sprintf("%s, %s\r\n",$this->row['id'], $this->row['bankno']); 
  14. file_put_contents("bankno_error.log"$error, FILE_APPEND); 
  15. ifstrlen($bankno) > 7 ){ 
  16. $sql = sprintf("update members set bankno = '%s' where id = '%s';"$bankno$this->row['id']); 
  17. $this->sql = $sql
  18. printf("%s\n",$this->sql); 
  19. try { 
  20. $dbh = new PDO("mysql:host=" . str_replace(':'';port='$dbhost) . ";dbname=$dbname"$dbuser$dbpwarray
  21. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
  22. PDO::MYSQL_ATTR_COMPRESS => true 
  23. ); 
  24. $sql = "select id,bankno from members order by id desc limit 50"
  25. $row = $dbh->query($sql); 
  26. $pool = array(); 
  27. while($member = $row->fetch(PDO::FETCH_ASSOC)) 
  28. $id = $member['id']; 
  29. while (true){ 
  30. if(count($pool) < 5){ 
  31. $pool[$id] = new Update($member); 
  32. $pool[$id]->start(); 
  33. break
  34. }else
  35. foreach ( $pool as $name => $worker){ 
  36. if(! $worker->isRunning()){ 
  37. unset($pool[$name]); 
  38. $dbh = null; 
  39. } catch (Exception $e) { 
  40. echo '【' , date('H:i:s') , '】''【系统错误】'$e->getMessage(), "\n"
  41. ?> 

pthreads Pool类

  1. <?php 
  2. class WebWorker extends Worker { 
  3. public function __construct(SafeLog $logger) { 
  4. $this->logger = $logger
  5. protected $loger
  6. class WebWork extends Stackable { 
  7. public function isComplete() { 
  8. return $this->complete; 
  9. public function run() { 
  10. $this->worker 
  11. ->logger 
  12. ->log("%s executing in Thread #%lu"
  13. __CLASS__$this->worker->getThreadId()); 
  14. $this->complete = true; 
  15. protected $complete
  16. class SafeLog extends Stackable { 
  17. protected function log($message$args = []) { 
  18. $args = func_get_args(); 
  19. if (($message = array_shift($args))) { 
  20. echo vsprintf( 
  21. "{$message}\n"$args); 
  22. $pool = new Pool(8, \WebWorker::class, [new SafeLog()]); 
  23. $pool->submit($w=new WebWork()); 
  24. $pool->submit(new WebWork()); 
  25. $pool->submit(new WebWork()); 
  26. $pool->submit(new WebWork()); 
  27. $pool->submit(new WebWork()); 
  28. $pool->submit(new WebWork()); 
  29. $pool->submit(new WebWork()); 
  30. $pool->submit(new WebWork()); 
  31. $pool->submit(new WebWork()); 
  32. $pool->submit(new WebWork()); 
  33. $pool->submit(new WebWork()); 
  34. $pool->submit(new WebWork()); 
  35. $pool->submit(new WebWork()); 
  36. $pool->submit(new WebWork()); 
  37. $pool->shutdown(); 
  38. $pool->collect(function($work){ 
  39. return $work->isComplete(); 
  40. }); 
  41. var_dump($pool); 

七、多线程文件安全读写

LOCK_SH 取得共享锁定(读取的程序)

LOCK_EX 取得独占锁定(写入的程序

LOCK_UN 释放锁定(无论共享或独占)

LOCK_NB 如果不希望 flock() 在锁定时堵塞

  1. <?php 
  2. $fp = fopen("/tmp/lock.txt""r+"); 
  3. if (flock($fp, LOCK_EX)) { // 进行排它型锁定 
  4. ftruncate($fp, 0); // truncate file 
  5. fwrite($fp"Write something here\n"); 
  6. fflush($fp); // flush output before releasing the lock 
  7. flock($fp, LOCK_UN); // 释放锁定 
  8. else { 
  9. echo "Couldn't get the lock!"
  10. fclose($fp); 
  11. $fp = fopen('/tmp/lock.txt''r+'); 
  12. if(!flock($fp, LOCK_EX | LOCK_NB)) { 
  13. echo 'Unable to obtain lock'
  14. exit(-1); 
  15. fclose($fp); 
  16. ?> 

八、多线程与数据连接

pthreads 与 pdo 同时使用是,需要注意一点,需要静态声明public static $dbh;并且通过单例模式访问数据库连接。

Worker 与 PDO

  1. <?php 
  2. class Work extends Stackable { 
  3. public function __construct() { 
  4. public function run() { 
  5. $dbh = $this->worker->getConnection(); 
  6. $sql = "select id,name from members order by id desc limit "
  7. $row = $dbh->query($sql); 
  8. while($member = $row->fetch(PDO::FETCH_ASSOC)){ 
  9. print_r($member); 
  10. class ExampleWorker extends Worker { 
  11. public static $dbh
  12. public function __construct($name) { 
  13. /* 
  14. * The run method should just prepare the environment for the work that is coming ... 
  15. */ 
  16. public function run(){ 
  17. self::$dbh = new PDO('mysql:host=...;dbname=example','www',''); 
  18. public function getConnection(){ 
  19. return self::$dbh
  20. $worker = new ExampleWorker("My Worker Thread"); 
  21. $work=new Work(); 
  22. $worker->stack($work); 
  23. $worker->start(); 
  24. $worker->shutdown(); 
  25. ?> 

Pool 与 PDO

在线程池中链接数据库

  1. # cat pool.php 
  2. <?php 
  3. class ExampleWorker extends Worker { 
  4. public function __construct(Logging $logger) { 
  5. $this->logger = $logger
  6. protected $logger
  7. /* the collectable class implements machinery for Pool::collect */ 
  8. class Work extends Stackable { 
  9. public function __construct($number) { 
  10. $this->number = $number
  11. public function run() { 
  12. $dbhost = 'db.example.com'// 数据库服务器 
  13. $dbuser = 'example.com'// 数据库用户名 
  14. $dbpw = 'password'// 数据库密码 
  15. $dbname = 'example_real'
  16. $dbh = new PDO("mysql:host=$dbhost;port=;dbname=$dbname"$dbuser$dbpwarray
  17. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF\''
  18. PDO::MYSQL_ATTR_COMPRESS => true, 
  19. PDO::ATTR_PERSISTENT => true 
  20. ); 
  21. $sql = "select OPEN_TIME, `COMMENT` from MT_TRADES where LOGIN='".$this->number['name']."' and CMD='' and `COMMENT` = '".$this->number['order'].":DEPOSIT'"; 
  22. #echo $sql
  23. $row = $dbh->query($sql); 
  24. $mt_trades = $row->fetch(PDO::FETCH_ASSOC); 
  25. if($mt_trades){ 
  26. $row = null; 
  27. $sql = "UPDATE db_example.accounts SET paystatus='成功', deposit_time='".$mt_trades['OPEN_TIME']."' where `order` = '".$this->number['order']."';"; 
  28. $dbh->query($sql); 
  29. #printf("%s\n",$sql); 
  30. $dbh = null; 
  31. printf("runtime: %s, %s, %s\n"date('Y-m-d H:i:s'), $this->worker->getThreadId() ,$this->number['order']); 
  32. class Logging extends Stackable { 
  33. protected static $dbh
  34. public function __construct() { 
  35. $dbhost = 'db.example.com'// 数据库服务器 
  36. $dbuser = 'example.com'// 数据库用户名 
  37. $dbpw = 'password'// 数据库密码 
  38. $dbname = 'example_real'// 数据库名 
  39. self::$dbh = new PDO("mysql:host=$dbhost;port=;dbname=$dbname"$dbuser$dbpwarray
  40. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF\''
  41. PDO::MYSQL_ATTR_COMPRESS => true 
  42. ); 
  43. protected function log($message$args = []) { 
  44. $args = func_get_args(); 
  45. if (($message = array_shift($args))) { 
  46. echo vsprintf("{$message}\n"$args); 
  47. protected function getConnection(){ 
  48. return self::$dbh
  49. $pool = new Pool(, \ExampleWorker::class, [new Logging()]); 
  50. $dbhost = 'db.example.com'// 数据库服务器 
  51. $dbuser = 'example.com'// 数据库用户名 
  52. $dbpw = 'password'// 数据库密码 
  53. $dbname = 'db_example'
  54. $dbh = new PDO("mysql:host=$dbhost;port=;dbname=$dbname"$dbuser$dbpwarray
  55. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF\''
  56. PDO::MYSQL_ATTR_COMPRESS => true 
  57. ); 
  58. $sql = "select `order`,name from accounts where deposit_time is null order by id desc"
  59. $row = $dbh->query($sql); 
  60. while($account = $row->fetch(PDO::FETCH_ASSOC)) 
  61. $pool->submit(new Work($account)); 
  62. $pool->shutdown(); 
  63. ?> 

进一步改进上面程序,我们使用单例模式 $this->worker->getInstance(); 全局仅仅做一次数据库连接,线程使用共享的数据库连接

  1. <?php 
  2. class ExampleWorker extends Worker { 
  3. #public function __construct(Logging $logger) { 
  4. $this->logger = $logger
  5. #} 
  6. #protected $logger
  7. protected static $dbh
  8. public function __construct() { 
  9. public function run(){ 
  10. $dbhost = 'db.example.com'// 数据库服务器 
  11. $dbuser = 'example.com'// 数据库用户名 
  12. $dbpw = 'password'// 数据库密码 
  13. $dbname = 'example'// 数据库名 
  14. self::$dbh = new PDO("mysql:host=$dbhost;port=;dbname=$dbname"$dbuser$dbpwarray
  15. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF\''
  16. PDO::MYSQL_ATTR_COMPRESS => true, 
  17. PDO::ATTR_PERSISTENT => true 
  18. ); 
  19. protected function getInstance(){ 
  20. return self::$dbh
  21. /* the collectable class implements machinery for Pool::collect */ 
  22. class Work extends Stackable { 
  23. public function __construct($data) { 
  24. $this->data = $data
  25. #print_r($data); 
  26. public function run() { 
  27. #$this->worker->logger->log("%s executing in Thread #%lu"__CLASS__$this->worker->getThreadId() ); 
  28. try { 
  29. $dbh = $this->worker->getInstance(); 
  30. #print_r($dbh); 
  31. $id = $this->data['id']; 
  32. $mobile = safenet_decrypt($this->data['mobile']); 
  33. #printf("%d, %s \n"$id$mobile); 
  34. if(strlen($mobile) > ){ 
  35. $mobile = substr($mobile, -); 
  36. if($mobile == 'null'){ 
  37. $sql = "UPDATE members_digest SET mobile = '".$mobile."' where id = '".$id."'"
  38. # printf("%s\n",$sql); 
  39. $dbh->query($sql); 
  40. $mobile = ''
  41. $sql = "UPDATE members_digest SET mobile = :mobile where id = :id"
  42. }else
  43. $sql = "UPDATE members_digest SET mobile = md(:mobile) where id = :id"
  44. $sth = $dbh->prepare($sql); 
  45. $sth->bindValue(':mobile'$mobile); 
  46. $sth->bindValue(':id'$id); 
  47. $sth->execute(); 
  48. #echo $sth->debugDumpParams(); 
  49. catch(PDOException $e) { 
  50. $error = sprintf("%s,%s\n"$mobile$id ); 
  51. file_put_contents("mobile_error.log"$error, FILE_APPEND); 
  52. #$dbh = null; 
  53. printf("runtime: %s, %s, %s, %s\n"date('Y-m-d H:i:s'), $this->worker->getThreadId() ,$mobile$id); 
  54. #printf("runtime: %s, %s\n"date('Y-m-d H:i:s'), $this->number); 
  55. $pool = new Pool(, \ExampleWorker::class, []); 
  56. #foreach (range(, ) as $number) { 
  57. $pool->submit(new Work($number)); 
  58. #} 
  59. $dbhost = 'db.example.com'// 数据库服务器 
  60. $dbuser = 'example.com'// 数据库用户名 
  61. $dbpw = 'password'// 数据库密码 
  62. $dbname = 'example'
  63. $dbh = new PDO("mysql:host=$dbhost;port=;dbname=$dbname"$dbuser$dbpwarray
  64. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF\''
  65. PDO::MYSQL_ATTR_COMPRESS => true 
  66. ); 
  67. #print_r($dbh); 
  68. #$sql = "select id, mobile from members where id < :id"
  69. #$sth = $dbh->prepare($sql); 
  70. #$sth->bindValue(':id',); 
  71. #$sth->execute(); 
  72. #$result = $sth->fetchAll(); 
  73. #print_r($result); 
  74. #$sql = "UPDATE members_digest SET mobile = :mobile where id = :id"
  75. #$sth = $dbh->prepare($sql); 
  76. #$sth->bindValue(':mobile''aa'); 
  77. #$sth->bindValue(':id',''); 
  78. #echo $sth->execute(); 
  79. #echo $sth->queryString; 
  80. #echo $sth->debugDumpParams(); 
  81. $sql = "select id, mobile from members order by id asc"// limit "; 
  82. $row = $dbh->query($sql); 
  83. while($members = $row->fetch(PDO::FETCH_ASSOC)) 
  84. #$order = $account['order']; 
  85. #printf("%s\n",$order); 
  86. //print_r($members); 
  87. $pool->submit(new Work($members)); 
  88. #unset($account['order']); 
  89. $pool->shutdown(); 
  90. ?> 

多线程中操作数据库总结

总的来说 pthreads 仍然处在发展中,仍有一些不足的地方,我们也可以看到pthreads的git在不断改进这个项目

数据库持久链接很重要,否则每个线程都会开启一次数据库连接,然后关闭,会导致很多链接超时。

  1. <?php 
  2. $dbh = new PDO('mysql:host=localhost;dbname=test'$user$passarray
  3. PDO::ATTR_PERSISTENT => true 
  4. )); 
  5. ?>

Tags: pthreads php多线程安装

分享到: