Install pthreads basically need to recompile PHP, plus--enable-maintainer-zts parameters, but with this document very few, bug will be many very many unexpected problems, build environment can only hehe, so this thing to play even, True multithreading or Python, C, etc.
First, 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
Installing Pthreads
PECL Install Pthreads
Second, 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 is tasks that is executed by Worker threads. You can 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;p ublic 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"), $sql 1 = new SQLQuery (' SELECT * FROM test ORDER BY id desc limit 1,5 '); $wor Ker->stack ($sql 1); $sql 2 = new SQLQuery (' SELECT * FROM test ORDER BY id desc limit 5,5 '); $worker->stack ($sql 2); $worke R->start (); $worker->shutdown ();? >
Four, mutual exclusion lock
What happens when a mutex is used? This can be used in situations where you need to control multiple threads at the same time with only one thread working. A simple counter program that shows the difference in the case of a mutex without a mutual 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 ($this handle); $counter ++;rewind ($this->handle); Fputs ($this->handle, $counter);p rintf ("Thread #%lu says:%s\n", $ This->getthreadid (), $counter), if ($this->mutex) mutex::unlock ($this->mutex);}} There is no mutex for ($i =0; $i <50; $i + +) {$threads [$i] = new Counterthread (); $threads [$i]->start ();} Join Mutex $mutex = Mutex::create (True); for ($i =0; $i <50; $i + +) {$threads [$i] = new Counterthread ($mutex); $threads [$i] >start ();} Mutex::unlock ($mutex); for ($i =0; $i <50; $i + +) {$threads [$i]->join ();} Mutex::d Estroy ($mutex);?
Multi-threaded vs. shared memory
In the example of shared memory, no lock is used, it may still work, and the function of the operating memory operation itself can be locked.
<?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) ;p rintf ("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);? >
Five, thread synchronization
There are scenarios where we don't want Thread->start () to start running the program, but instead want the thread to wait for our command. Thread−>wait (); Thread−>start () After the thread does not run immediately, only receive thread->notify (); After the signal is sent, the
is not run
<?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);p rintf ("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);? >
Six, thread pool
A pool class
<?phpclass Update extends Thread {public $running = false;public $row = Array ();p ublic function __construct ($row) {$thi S->row = $row; $this->sql = null;} Public Function Run () {if (strlen ($this->row[' Bankno ') >) {$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[' I d ']); $this->sql = $sql;} printf ("%s\n", $this->sql);}} Class Pool {public $pool = array ();p ublic 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 Function 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 (': ', ';p ort= ', $dbhost). ";d bname= $dbname", $dbuser, $DBPW, array (pdo::mysql_attr_init_command = ' SET NAMES \ ' utf8\ ', pdo::mysql_attr_ COMPRESS = (true)); $sql = "Select Id,bankno from the 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 into task into 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 when the line Cheng executes start unified boot, the following example is to create a new thread as soon as there is idle in the thread pool.
<?phpclass Update extends Thread {public $running = false;public $row = Array ();p ublic function __construct ($row) {$thi S->row = $row; $this->sql = Null;//print_r ($this->row);} Public Function Run () {if (strlen ($this->row[' Bankno ') >) {$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[' I d ']); $this->sql = $sql;} printf ("%s\n", $this->sql);}} try {$dbh = new PDO ("mysql:host=". Str_replace (': ', ';p ort= ', $dbhost). ";d bname= $dbname", $dbuser, $DBPW, array (pdo::mysql_attr_init_command = ' SET NAMES \ ' utf8\ ', pdo::mysql_attr_ COMPRESS = (true)); $sql = "Select Id,bankno from the members order by id desc LIMIT"; $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 = arr Ay_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);
Seven, multi-threaded file security Read and write
Lock_sh Get a shared lock (read program)
LOCK_EX Get exclusive Lock (write program
Lock_un release lock (either shared or exclusive)
LOCK_NB If you do not want flock () to block when locked
<?PHP$FP = fopen ("/tmp/lock.txt", "r+"), if (Flock ($FP, LOCK_EX)) {//Type 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);? >
Eight, multi-threading and data connections
Pthreads is used in conjunction with PDO, it is important to note that you need to statically declare public static $DBH and access the database connection through singleton mode.
Worker and PDO
<?phpclass work extends Stackable {public Function __construct () {}public function run () {$DBH = $this->worker->g Etconnection (); $sql = "Select Id,name from the members ORDER by id desc-Limit"; $row = $dbh->query ($sql); while ($member = $r Ow->fetch (PDO::FETCH_ASSOC)) {Print_r ($member);}}} Class Exampleworker extends Worker {public static $DBH;p ublic function __construct ($name) {}/** The Run method should just Prepare the environment for the work this 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
Link a database in a 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 __construc T ($number) {$this->number = $number;} Public Function Run () {$dbhost = ' db.example.com ';//database Server $dbuser = ' example.com ';//database user name $DBPW = ' password ';//Database Password $dbname = ' example_real '; $dbh = new PDO ("mysql:host= $dbhost;p ort=;d bname= $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 ' = '. $th is->number[' order ']. ":D Eposit ' "; #echo $sql; $row = $dbh->query ($sql); $mt _trades = $row->fetch (PDO::FETCH_ASSOC); if ($mt _trades) {$row = null; $sql = "UPDATE db_example.accounts SET paystatus= ' succeeded ', 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 ']);}} Class Logging extends Stackable {protected static $DBH;p ublic function __construct () {$dbhost = ' db.example.com ';//Database service Device $dbuser = ' example.com '; Database user name $DBPW = ' password '; Database Password $dbname = ' example_real '; Database name self:: $DBH = new PDO ("mysql:host= $dbhost;p ort=;d bname= $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 user Name $DBPW = ' PAssword '; Database Password $dbname = ' db_example '; $dbh = new PDO ("mysql:host= $dbhost;p ort=;d bname= $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 for the ORDER by id desc "; $row = $dbh->query ($sql), while ($account = $row->fetch (pdo::fet CH_ASSOC) {$pool->submit (new Work ($account));} $pool->shutdown ();? >
To further improve the above procedure, we use a singleton mode $this->worker->getinstance (); The global database connection is only made once, and the thread uses the shared database connection
<?phpclass Exampleworker extends Worker {#public function __construct (Logging $logger) {# $this->logger = $logger; # } #protected $logger;p rotected static $dbh;p ublic function __construct () {}public function run () {$dbhost = ' Db.example.com '; Database server $dbuser = ' example.com '; Database user name $DBPW = ' password '; Database Password $dbname = ' example '; Database name self:: $DBH = new PDO ("mysql:host= $dbhost;p ort=;d bname= $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 __construc T ($data) {$this->data = $data; #print_r ($data);} Public Function Run () {# $this->worker->logger->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 =: I D ";} else{$sql = "UPDATE members_digest SET mobile = MD (: mobile) WHERE id =: id";} $sth = $dbh->prepare ($sql) $sth->bindvalue (': Mobile ', $mobile); $sth->bindvalue (': Id ', $id); $sth Execute (); #echo $sth->debugdumpparams ();} catch (Pdoexception $e) {$error = sprintf ("%s,%s\n", $mobile, $id) file_put_contents ("Mobile_error.log", $error, File_ APPEND);} # $DBH = null;printf ("Runtime:%s,%s,%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 user name $DBPW = ' password '; Database Password $dbname = ' example '; $dbh = new PDO ("mysql:host= $dbhost;p ort=;d bname= $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 the members where ID <: ID "; # $sth = $dbh->prepare ($sql); # $sth->bindvalue (': id '); # $sth->execute (); # $result = $sth->fetchall (); #print_r ($result); # # $sql = "UPDATE members_digest SET mobile =: mobile WHERE id =: id"; # $st h = $dbh->prepare ($sql); # $sth->bindvalue (': Mobile ', ' AA '); # $sth->bindvalue (': id ', '); #echo $sth Execute (); #echo $sth->querystring; #echo $sth->debugdumpparams (); $sql = "SELECT ID, mobile from members order by ID a SC "; 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 ();? >
Operations Database summary in multi-threading
In general Pthreads is still in development, there are still some deficiencies, we can also see pthreads git is constantly improving the project
Database persistent links are important, or each thread will open a database connection and then close, causing many links to time out.
<?PHP$DBH = new PDO (' Mysql:host=localhost;dbname=test ', $user, $pass, array (pdo::attr_persistent = true)); >
About PHP pthreads multi-threaded installation and use of relevant knowledge, first introduce to you here, follow up will continue to update.