Install and use multiple threads in phppthreads

Source: Internet
Author: User
Tags flock zts
This article describes how to install and use multiple threads in phppthreads. if you need to install Pthreads, you can refer to installing Pthreads and recompile PHP. the -- enable-maintainer-zts parameter is added, however, this document is rarely used. there will be many and many unexpected bugs in the bug generation environment, so you can only use it to play around. for real multithreading, you can still use Python, C, and so on.

I. Installation

Php-7.0.2 is used here

./configure \--prefix=/usr/local/php7 \--with-config-file-path=/etc \--with-config-file-scan-dir=/etc/php.d \--enable-debug \--enable-maintainer-zts \--enable-pcntl \--enable-fpm \--enable-opcache \--enable-embed=shared \--enable-json=shared \--enable-phpdbg \--with-curl=shared \--with-mysql=/usr/local/mysql \--with-mysqli=/usr/local/mysql/bin/mysql_config \--with-pdo-mysql

Make & make install

Install pthreads

Pecl install pthreads

II. Thread

<?php#1$thread = new class extends Thread {public function run() {echo "Hello World {$this->getThreadId()}\n"; } };$thread->start() && $thread->join();#2class workerThread extends Thread { public function __construct($i){$this->i=$i;}public function run(){while(true){echo $this->i."\n";sleep(1);} } }for($i=0;$i<50;$i++){$workers[$i]=new workerThread($i);$workers[$i]->start();}?>

III. Worker and Stackable

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

<?phpclass SQLQuery extends Stackable {public function __construct($sql) {$this->sql = $sql;}public function run() {$dbh = $this->worker->getConnection();$row = $dbh->query($this->sql);while($member = $row->fetch(PDO::FETCH_ASSOC)){print_r($member);}}}class ExampleWorker extends Worker {public static $dbh;public function __construct($name) {}public function run(){self::$dbh = new PDO('mysql:host=10.0.0.30;dbname=testdb','root','123456');}public function getConnection(){return self::$dbh;}}$worker = new ExampleWorker("My Worker Thread");$sql1 = new SQLQuery('select * from test order by id desc limit 1,5');$worker->stack($sql1);$sql2 = new SQLQuery('select * from test order by id desc limit 5,5');$worker->stack($sql2);$worker->start();$worker->shutdown();?>

IV. mutex lock

Under what circumstances will mutex lock be used? It can be used when you need to control multiple threads and only one thread can work at a time. A simple counter program is used to describe the differences in the case of mutex lock.

<? Php $ counter = 0; $ handle = fopen ("/tmp/counter.txt", "w"); fwrite ($ handle, $ counter); fclose ($ handle ); class CounterThread extends Thread {public function _ construct ($ mutex = null) {$ this-> mutex = $ mutex; $ this-> handle = fopen ("/tmp/counter.txt", "w +");} public function _ destruct () {fclose ($ this-> handle );} public function run () {if ($ this-> mutex) $ locked = Mutex: lock ($ this-> mutex); $ counter = intval (fgets ($ thi S-> handle); $ counter ++; rewind ($ this-> handle); fputs ($ this-> handle, $ counter ); printf ("Thread # % lu says: % s \ n", $ this-> getThreadId (), $ counter); if ($ this-> mutex) Mutex :: unlock ($ this-> mutex) ;}// no mutex lock for ($ I = 0; $ I <50; $ I ++) {$ threads [$ I] = new CounterThread (); $ threads [$ I]-> start ();} // add the mutex lock $ Mutex = mutex :: create (true); for ($ I = 0; $ I <50; $ I ++) {$ threads [$ I] = new CounterThread ($ mutex ); $ threads [$ I]-> start ();} Mute X: unlock ($ mutex); for ($ I = 0; $ I <50; $ I ++) {$ threads [$ I]-> join ();} mutex: destroy ($ mutex);?>

Multithreading and shared memory

In the example of shared memory, if no lock is used, it may still work normally, and the working memory operation itself may have the lock function.

<?php$tmp = tempnam(__FILE__, 'PHP');$key = ftok($tmp, 'a');$shmid = shm_attach($key);$counter = 0;shm_put_var( $shmid, 1, $counter );class CounterThread extends Thread {public function __construct($shmid){$this->shmid = $shmid;}public function run() {$counter = shm_get_var( $this->shmid, 1 );$counter++;shm_put_var( $this->shmid, 1, $counter );printf("Thread #%lu says: %s\n", $this->getThreadId(),$counter);}}for ($i=0;$i<100;$i++){$threads[] = new CounterThread($shmid);}for ($i=0;$i<100;$i++){$threads[$i]->start();}for ($i=0;$i<100;$i++){$threads[$i]->join();}shm_remove( $shmid );shm_detach( $shmid );?>

5. Thread synchronization

In some scenarios, we do not want thread-> start () to start the program, but want the thread to wait for our command. Thread −> wait (); the test function is that the thread does not run immediately after thread −> start (), and runs only after receiving the signal from thread-> notify ();

<?php$tmp = tempnam(__FILE__, 'PHP');$key = ftok($tmp, 'a');$shmid = shm_attach($key);$counter = 0;shm_put_var( $shmid, 1, $counter );class CounterThread extends Thread {public function __construct($shmid){$this->shmid = $shmid;}public function run() {$this->synchronized(function($thread){$thread->wait();}, $this);$counter = shm_get_var( $this->shmid, 1 );$counter++;shm_put_var( $this->shmid, 1, $counter );printf("Thread #%lu says: %s\n", $this->getThreadId(),$counter);}}for ($i=0;$i<100;$i++){$threads[] = new CounterThread($shmid);}for ($i=0;$i<100;$i++){$threads[$i]->start();}for ($i=0;$i<100;$i++){$threads[$i]->synchronized(function($thread){$thread->notify();}, $threads[$i]);}for ($i=0;$i<100;$i++){$threads[$i]->join();}shm_remove( $shmid );shm_detach( $shmid );?> 

6. thread pool

One Pool class

<? Phpclass Update extends Thread {public $ running = false; public $ row = array (); public function _ construct ($ row) {$ this-> row = $ row; $ this-> SQL = null;} public function run () {if (strlen ($ this-> row ['bankno'])> 100) {$ bankno = safenet_decrypt ($ this-> row ['bankno']);} else {$ error = sprintf ("% s, % s \ r \ n ", $ this-> row ['id'], $ this-> row ['bankno']); file_put_contents ("bankno_error.log", $ error, FILE_APPEND);} if (Strlen ($ bankno)> 7) {$ SQL = sprintf ("update members set bankno = '% s' where id =' % s';", $ bankno, $ this-> row ['id']); $ this-> SQL = $ SQL;} printf ("% s \ n", $ this-> SQL );}} class Pool {public $ pool = array (); public function _ construct ($ count) {$ this-> count = $ count;} public function push ($ row) {if (count ($ this-> pool) <$ this-> count) {$ this-> pool [] = new Update ($ row); return true ;} else {return false ;}} public fun Ction start () {foreach ($ this-> pool as $ id = >$ worker) {$ this-> pool [$ id]-> start ();}} public function join () {foreach ($ this-> pool as $ id = >$ worker) {$ this-> pool [$ id]-> join ();}} public function clean () {foreach ($ this-> pool as $ id => $ worker) {if (! $ Worker-> isRunning () {unset ($ this-> pool [$ id]) ;}}try {$ dbh = new PDO ("mysql: host = ". str_replace (':', '; port =', $ dbhost ). "; dbname = $ dbname", $ dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf8 \ '', PDO :: MYSQL_ATTR_COMPRESS => true); $ SQL = "select id, bankno from members order by id desc"; $ row = $ dbh-> query ($ SQL ); $ pool = new Pool (5); while ($ member = $ row-> fetch (PDO: FETCH_ASSOC )) {While (true) {if ($ pool-> push ($ member) {// Press the task into the pool break;} else {// if the pool is full, start the thread $ pool-> start (); $ pool-> join (); $ pool-> clean () ;}}$ pool-> start (); $ pool-> join (); $ dbh = null;} catch (Exception $ e) {echo '[', date ('H: I: s '), ']', 'system error', $ e-> getMessage (), "\ n" ;}?>

Dynamic queue thread pool

The above example is to execute start after the thread pool is full. the following example is to create a new thread immediately as long as the thread pool is idle.

<? Phpclass Update extends Thread {public $ running = false; public $ row = array (); public function _ construct ($ row) {$ this-> row = $ row; $ this-> SQL = null; // print_r ($ this-> row);} public function run () {if (strlen ($ this-> row ['bankno'])> 100) {$ bankno = safenet_decrypt ($ this-> row ['bankno']);} else {$ error = sprintf ("% s, % s \ r \ n", $ this-> row ['id'], $ this-> row ['bankno']); file_put_contents ("bankno_error.log", $ err Or, FILE_APPEND);} if (strlen ($ bankno)> 7) {$ SQL = sprintf ("update members set bankno = '% s' where id =' % s '; ", $ bankno, $ this-> row ['id']); $ this-> SQL = $ SQL;} printf (" % s \ n ", $ this-> SQL) ;}}try {$ dbh = new PDO ("mysql: host = ". str_replace (':', '; port =', $ dbhost ). "; dbname = $ dbname", $ dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf8 \ '', PDO :: MYSQL_ATTR_COMPRESS => true); $ SQL = "sel Ect id, bankno from members order by id desc limit 50 "; $ row = $ dbh-> query ($ SQL); $ pool = array (); while ($ member = $ row-> fetch (PDO: FETCH_ASSOC) {$ id = $ member ['id']; while (true) {if (count ($ pool) <5) {$ pool [$ id] = new Update ($ member); $ pool [$ id]-> start (); break;} else {foreach ($ pool as $ name => $ worker) {if (! $ Worker-> isRunning () {unset ($ pool [$ name]) ;}}}$ dbh = null;} catch (Exception $ e) {echo '[', date ('H: I: s'), ']', '[system error]', $ e-> getMessage (), "\ n" ;}?>

Pthreads Pool class

<?phpclass WebWorker extends Worker {public function __construct(SafeLog $logger) {$this->logger = $logger;}protected $loger;}class WebWork extends Stackable {public function isComplete() {return $this->complete;}public function run() {$this->worker->logger->log("%s executing in Thread #%lu",__CLASS__, $this->worker->getThreadId());$this->complete = true;}protected $complete;}class SafeLog extends Stackable {protected function log($message, $args = []) {$args = func_get_args();if (($message = array_shift($args))) {echo vsprintf("{$message}\n", $args);}}}$pool = new Pool(8, \WebWorker::class, [new SafeLog()]);$pool->submit($w=new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->submit(new WebWork());$pool->shutdown();$pool->collect(function($work){return $work->isComplete();});var_dump($pool); 

VII. secure read/write of multi-threaded files

LOCK_SH get Share Lock (read program)

LOCK_EX gets an exclusive lock (written program

LOCK_UN release lock (whether shared or exclusive)

LOCK_NB if you do not want flock () to be blocked during Lock

<? Php $ fp = fopen ("/tmp/lock.txt", "r +"); if (flock ($ fp, LOCK_EX )) {// lock ftruncate ($ fp, 0); // truncate filefwrite ($ fp, "Write something here \ n"); fflush ($ fp ); // flush output before releasing the lockflock ($ fp, LOCK_UN); // release lock} else {echo "Couldn't get the lock! ";}Fclose ($ fp); $ fp = fopen ('/tmp/lock.txt', 'R + '); if (! Flock ($ fp, LOCK_EX | LOCK_NB) {echo 'unable to obtain lock'; exit (-1) ;}fclose ($ fp);?>

8. multi-thread and data connection

Pthreads and pdo are used at the same time. Note that public static $ dbh must be declared statically and the database connection can be accessed in Singleton mode.

Worker and PDO

<?phpclass Work extends Stackable {public function __construct() {}public function run() {$dbh = $this->worker->getConnection();$sql = "select id,name from members order by id desc limit ";$row = $dbh->query($sql);while($member = $row->fetch(PDO::FETCH_ASSOC)){print_r($member);}}}class ExampleWorker extends Worker {public static $dbh;public function __construct($name) {}/** The run method should just prepare the environment for the work that is coming ...*/public function run(){self::$dbh = new PDO('mysql:host=...;dbname=example','www','');}public function getConnection(){return self::$dbh;}}$worker = new ExampleWorker("My Worker Thread");$work=new Work();$worker->stack($work);$worker->start();$worker->shutdown();?> 

Pool and PDO

Connect to the database in the thread pool

# Cat pool. php <? Phpclass ExampleWorker extends Worker {public function _ construct (Logging $ logger) {$ this-> logger = $ logger;} protected $ logger ;} /* the collectable class implements machinery for Pool: collect */class Work extends Stackable {public function _ construct ($ number) {$ this-> number = $ number ;} public function run () {$ dbhost = 'DB .example.com '; // database server $ dbuser = 'example. com '; // database username $ dbpw = 'password '; // Database password $ dbname = 'example _ real'; $ dbh = new PDO ("mysql: host = $ dbhost; port =; dbname = $ dbname", $ dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf \ ', PDO: MYSQL_ATTR_COMPRESS => true, PDO: ATTR_PERSISTENT => true )); $ SQL = "select OPEN_TIME, 'comment' from MT_TRADES where LOGIN = '". $ this-> number ['name']. "'and CMD ='' and 'comment' = '". $ this-> number ['order']. ": DEPOSIT '"; # echo $ SQL; $ ro W = $ dbh-> query ($ SQL); $ mt_trades = $ row-> fetch (PDO: FETCH_ASSOC); if ($ mt_trades) {$ row = null; $ SQL = "UPDATE db_example.accounts SET paystatus = 'success', deposit_time = '". $ mt_trades ['open _ time']. "'where'order' = '". $ this-> number ['order']. "';"; $ dbh-> query ($ SQL); # printf ("% s \ n", $ SQL) ;}$ dbh = null; printf ("runtime: % s, % s, % s \ n ", date ('Y-m-d H: I: s'), $ this-> worker-> getThreadId (), $ this-> number ['order']);} cl Ass Logging extends Stackable {protected static $ dbh; public function _ construct () {$ dbhost = 'DB .example.com '; // database server $ dbuser = 'example. com '; // database username $ dbpw = 'password'; // database password $ dbname = 'example _ real'; // database name self :: $ dbh = new PDO ("mysql: host = $ dbhost; port =; dbname = $ dbname", $ dbuser, $ dbpw, array (PDO :: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf \ '', PDO: MYSQL_ATTR_COMPRESS => true);} protected Function log ($ message, $ args = []) {$ args = func_get_args (); if ($ message = array_shift ($ args ))) {echo vsprintf ("{$ message} \ n", $ args) ;}} protected function getConnection () {return self ::$ dbh ;}} $ pool = new Pool (, \ ExampleWorker: class, [new Logging ()]); $ dbhost = 'DB .example.com '; // database server $ dbuser = 'example. com '; // database username $ dbpw = 'password'; // database password $ dbname = 'DB _ example'; $ dbh = new PDO ("mysql: host = $ Dbhost; port =; dbname = $ dbname ", $ dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf \ ', PDO :: MYSQL_ATTR_COMPRESS => true); $ SQL = "select 'order', name from accounts where deposit_time is null order by id desc "; $ row = $ dbh-> query ($ SQL); while ($ account = $ row-> fetch (PDO: FETCH_ASSOC )) {$ pool-> submit (new Work ($ account) ;}$ pool-> shutdown ();?>

To further improve the above program, we use the Singleton mode $ this-> worker-> getInstance (); only one database connection is performed globally, and threads use a shared database connection.

<? Phpclass ExampleWorker extends Worker {# public function _ construct (Logging $ logger) {#$ this-> logger = $ logger ;#}# protected $ logger; protected static $ dbh; public function _ construct () {} public function run () {$ dbhost = 'DB .example.com '; // database server $ dbuser = 'example. com '; // database username $ dbpw = 'password'; // database password $ dbname = 'example'; // database name self :: $ dbh = new PDO ("mysql: host = $ dbhost; port =; dbname = $ dbname", $ Dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf \ '', PDO: MYSQL_ATTR_COMPRESS => true, PDO :: ATTR_PERSISTENT => true);} protected function getInstance () {return self: $ dbh ;}/ * the collectable class implements machinery for Pool :: collect */class Work extends Stackable {public function _ construct ($ data) {$ this-> data = $ data; # print_r ($ data);} public function run () {# $ this-> worker-> l Ogger-> log ("% s executing in Thread # % lu", _ CLASS __, $ this-> worker-> getThreadId ()); try {$ dbh = $ this-> worker-> getInstance (); # print_r ($ dbh); $ id = $ this-> data ['id']; $ mobile = safenet_decrypt ($ this-> data ['mobile']); # printf ("% d, % s \ n", $ id, $ mobile ); if (strlen ($ mobile)>) {$ mobile = substr ($ mobile,-);} if ($ mobile = 'null ') {# $ SQL = "UPDATE members_digest SET mobile = '". $ mobile. "'Where id = '". $ id. "'"; # Printf ("% s \ n", $ SQL); # $ dbh-> query ($ SQL); $ mobile = ''; $ SQL = "UPDATE members_digest SET mobile =: mobile where id =: id";} else {$ SQL = "UPDATE members_digest SET mobile = md (: mobile) where id =: id ";}$…… =dbdbh-> prepare ($ SQL); $……-> bindValue (': mobile', $ mobile); $……-> bindValue (': ID', $ id); $ Something-> execute (); # echo $ Something-> debugDumpParams ();} catch (PDOException $ e) {$ error = sprintf ("% s, % s \ n", $ mobil E, $ id); file_put_contents ("mobile_error.log", $ error, FILE_APPEND) ;}# $ dbh = null; printf ("runtime: % s, % s \ n ", date ('Y-m-d H: I: s'), $ this-> worker-> getThreadId (), $ mobile, $ id ); # printf ("runtime: % s, % s \ n", date ('Y-m-d H: I: s'), $ this-> number );}} $ pool = new Pool (, \ ExampleWorker: class, []); # foreach (range (,) as $ number) {# $ pool-> submit (new Work ($ number); #}$ dbhost = 'DB .example.com '; // Database Server $ dbuser = 'example. com '; // database username $ dbpw = 'password'; // database password $ dbname = 'example'; $ dbh = new PDO ("mysql: host = $ dbhost; port =; dbname = $ dbname ", $ dbuser, $ dbpw, array (PDO: MYSQL_ATTR_INIT_COMMAND => 'set NAMES \ 'utf \ ', PDO :: MYSQL_ATTR_COMPRESS => true); # print_r ($ dbh); # $ SQL = "select id, mobile from members where id <: id "; # $ things = $ dbh-> prepare ($ SQL); # $ things-> bindValue (': ID',); # $ things-> execute (); # $ resul T = $ Something-> fetchAll (); # print_r ($ result); ##$ SQL = "UPDATE members_digest SET mobile =: mobile where id =: id "; # $ things = $ dbh-> prepare ($ SQL); # $ things-> bindValue (': mobile', 'A'); # $ things-> bindValue (': ID', ''); # echo $ Something-> execute (); # echo $ Something-> queryString; # echo $ Something-> debugDumpParams (); $ SQL = "select id, mobile from members order by id asc"; // limit "; $ row = $ dbh-> query ($ SQL ); while ($ members = $ row-> fetch (PDO :: FETCH_ASSOC) {# $ order = $ account ['order']; # printf ("% s \ n", $ order); // print_r ($ members ); $ pool-> submit (new Work ($ members); # unset ($ account ['order']);} $ pool-> shutdown ();?>

Summary of multi-thread database operations

In general, pthreads is still in development and there are still some shortcomings. we can also see that pthreads git is constantly improving this project.

The persistent connection of the database is very important. otherwise, each thread starts a database connection and closes the connection, which may cause many connections to time out.

<?php$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));?>

We will introduce you to the installation and use of php pthreads multithreading, which will be updated in the future.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.