PHP pthreads _php instance of multi-threading installation and usage

Source: Internet
Author: User
Tags flock getmessage mutex php class prepare sprintf strlen zts

Install pthreads basically need to recompile PHP, plus--enable-maintainer-zts parameter, but use this document very little; Bugs can be a lot of unexpected problems, build environment can only hehe, so this thing to play even if, Real multithreading or using Python, C, etc.

First, installation

This is php-7.0.2.

./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

Second, Thread

<?php
#1
$thread = new class extends thread {public
function run () {
echo] Hello World {$this->gett Hreadid ()}\n "; 
} 
};
$thread->start () && $thread->join ();
#2
class Workerthread extends Thread {public 
function __construct ($i) {
$this->i= $i;
}
The 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 ();
}
? >

Third, Worker and stackable

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

<?php
class 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");
$sql 1 = new SQLQuery (' SELECT * FROM test-id desc limit 1,5 ');
$worker->stack ($sql 1);
$sql 2 = new SQLQuery (' SELECT * FROM test-id desc limit 5,5 ');
$worker->stack ($sql 2);
$worker->start ();
$worker->shutdown ();
? >

Iv. Mutual-exclusion locks

Under what circumstances will a mutex be used? Can be used when you need to control multiple threads at the same time that only one thread is working. A simple counter program that indicates a different

without a mutex.

<?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->handl
E = fopen ("/tmp/counter.txt", "w+"); The Public Function __destruct () {fclose ($this->handle),} public function run () {if ($this->mutex) $locked =mutex::lo
CK ($this->mutex);
$counter = Intval (fgets ($this->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 for ($i =0 $i <50; $i + +) {$threads [$i] = new Counterthread (); $threads [$i]->start ();}//Join Mutex $mutex = Mut
Ex::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-threading and shared memory

In the case of shared memory, no lock is used, and it may still work, and the working memory operation itself has the function of locking

<?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);
? >

Five, thread synchronization

There are scenarios where we don't want Thread->start () to start running the program, but we want the thread to wait for our command. The thread−>wait () is Thread−>start () after the thread does not run immediately and only receives the thread->notify (); The

is not run until the signal is emitted.

<?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);

Six, thread pool

A pool class

<?php class 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 ']) > {$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 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 DESC";
$row = $dbh->query ($sql);
$pool = new Pool (5); while ($member = $row->fetch (PDO::FETCH_ASSOC)) {while (true) {if ($pool->push ($member)) {//pressing 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 example above is to perform start unified startup after the line Cheng, and the following example is to create a new thread as soon as there is idle in the thread pool.

<?php class 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 ']) > {$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); The 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 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

<?php class Webworker extends Worker {public function __construct (Safelog $logger) {$this->logger = $logger;} PR
Otected $loger; Class WebWork extends Stackable {public Function iscomplete () {return $this->complete;} public Function run () {$t
His->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);

Seven, multithreading file security Read and write

Lock_sh access to shared locks (read programs)

LOCK_EX Get exclusive Lock (written program

Lock_un release locks (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)) {//For exclusive locking
ftruncate ($fp, 0);//Truncate file
fwrite ($fp, "Write something here\n"); 
   fflush ($FP); Flush output before releasing the lock
flock ($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, multithreading and data Connectivity

Pthreads and PDO are used at the same time, you need to be aware of the need to statically declare the public static $DBH, and to access the database connection through a single case mode.

Worker and PDO

<?php
class Work extends stackable {public
function __construct () {
} public
function run () {
$ DBH = $this->worker->getconnection ();
$sql = "Select Id,name from 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 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 database in thread pool

# cat pool.php <?php class Exampleworker extends Worker {public function __construct (Logging $logger) {$this->log
GER = $logger;
} protected $logger; }/* The collectable class implements machinery for Pool::collect */class Work extends Stackable {public Function __cons Truct ($number) {$this->number = $number;} public Function Run () {$dbhost = ' db.example.com ';//database Server $dbuser = ' EX Ample.com '; Database username $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 ' = ' ". $this->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= ' success ', Deposit_time= '. $mt _trades[' Open_time ']. "' WHERE ' order ' = '". $this->number[' an 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 '); The class 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;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 VSPR
Intf ("{$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;p ort=;d bname= $dbname", $dbuser, $DBPW, Array (Pdo::mysql_attr_init_command => '
SET NAMES \ ' utf\ ', pdo::mysql_attr_compress => true);
$sql = "SELECT ' Order", the name from accounts where deposit_time be null ORDER by id DESC ";
$row = $dbh->query ($sql); while ($account = $row->fetch (PDO::FETCH_ASSOC)) {$pool->submit (new Work ($account));} $pool->shutdown ();?  >

Further improve the above program, we use the single case mode $this->worker->getinstance (); Global only once database connection, thread use shared database connection

<?php class Exampleworker extends Worker {#public function __construct (Logging $logger) {# $this->logger = $logge
R
#} #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;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 __constr UCT ($data) {$this->data = $data; #print_r ($data);} public Function Run () {# $this->worker->logger->log ("%s E
Xecuting 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 mobi
Le = ' ". $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";} $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 username $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 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 ';
# $sth = $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 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 operation database in multi-threading

Overall pthreads is still in development, there are still some deficiencies, and we can see that pthreads's git is constantly improving the project

Database persistent links are important, otherwise each thread will open a database connection and then close, causing many links to timeout.

<?php
$dbh = new PDO (' Mysql:host=localhost;dbname=test ', $user, $pass, Array (
pdo::attr_persistent => True
);
? >

About the PHP pthreads installation and use of the relevant knowledge, first to introduce to you here, follow-up will continue to update.

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.