Related
Is there a realistic way of implementing a multi-threaded model in PHP whether truly, or just simulating it. Some time back it was suggested that you could force the operating system to load another instance of the PHP executable and handle other simultaneous processes.
The problem with this is that when the PHP code finished executing the PHP instance remains in memory because there is no way to kill it from within PHP. So if you are simulating several threads you can imagine whats going to happen. So I am still looking for a way multi-threading can be done or simulated effectively from within PHP. Any ideas?
Warning: This extension is considered unmaintained and dead.
Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP is therefore restricted to CLI-based applications only.
Warning: pthreads (v3) can only be used with PHP 7.2+: This is due to ZTS mode being unsafe in 7.0 and 7.1.
https://www.php.net/manual/en/intro.pthreads.php
Multi-threading is possible in php
Yes you can do multi-threading in PHP with pthreads
From the PHP documentation:
pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.
Warning:
The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.
Simple Test
#!/usr/bin/php
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = mt_rand(1, 10);
printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
sleep($sleep);
printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg);
}
}
}
// Create a array
$stack = array();
//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
$stack[] = new AsyncOperation($i);
}
// Start The Threads
foreach ( $stack as $t ) {
$t->start();
}
?>
First Run
12:00:06pm: A -start -sleeps 5
12:00:06pm: B -start -sleeps 3
12:00:06pm: C -start -sleeps 10
12:00:06pm: D -start -sleeps 2
12:00:08pm: D -finish
12:00:09pm: B -finish
12:00:11pm: A -finish
12:00:16pm: C -finish
Second Run
12:01:36pm: A -start -sleeps 6
12:01:36pm: B -start -sleeps 1
12:01:36pm: C -start -sleeps 2
12:01:36pm: D -start -sleeps 1
12:01:37pm: B -finish
12:01:37pm: D -finish
12:01:38pm: C -finish
12:01:42pm: A -finish
Real World Example
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if (($url = $this->url)) {
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents($url);
} else
printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
}
}
$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
printf("Request took %f seconds to start ", microtime(true) - $t);
while ( $g->isRunning() ) {
echo ".";
usleep(100);
}
if ($g->join()) {
printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
} else
printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
why don't you use popen?
for ($i=0; $i<10; $i++) {
// open ten processes
for ($j = 0; $j < 10; $j++) {
$pipe[$j] = popen('script2.php', 'w');
}
// wait for them to finish
for ($j = 0; $j < 10; ++$j) {
pclose($pipe[$j]);
}
}
Threading isn't available in stock PHP, but concurrent programming is possible by using HTTP requests as asynchronous calls.
With the curl's timeout setting set to 1 and using the same session_id for the processes you want to be associated with each other, you can communicate with session variables as in my example below. With this method you can even close your browser and the concurrent process still exists on the server.
Don't forget to verify the correct session ID like this:
http://localhost/test/verifysession.php?sessionid=[the correct id]
startprocess.php
$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];
process1.php
set_time_limit(0);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
function checkclose()
{
global $_SESSION;
if ($_SESSION["closesession"])
{
unset($_SESSION["closesession"]);
die();
}
}
while(!$close)
{
session_start();
$_SESSION["test"] = rand();
checkclose();
session_write_close();
sleep(5);
}
verifysession.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
closeprocess.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
While you can't thread, you do have some degree of process control in php. The two function sets that are useful here are:
Process control functions
http://www.php.net/manual/en/ref.pcntl.php
POSIX functions
http://www.php.net/manual/en/ref.posix.php
You could fork your process with pcntl_fork - returning the PID of the child. Then you can use posix_kill to despose of that PID.
That said, if you kill a parent process a signal should be sent to the child process telling it to die. If php itself isn't recognising this you could register a function to manage it and do a clean exit using pcntl_signal.
using threads is made possible by the pthreads PECL extension
http://www.php.net/manual/en/book.pthreads.php
I know this is an old question but for people searching, there is a PECL extension written in C that gives PHP multi-threading capability now, it's located here https://github.com/krakjoe/pthreads
You can use exec() to run a command line script (such as command line php), and if you pipe the output to a file then your script won't wait for the command to finish.
I can't quite remember the php CLI syntax, but you'd want something like:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
I think quite a few shared hosting servers have exec() disabled by default for security reasons, but might be worth a try.
You could simulate threading. PHP can run background processes via popen (or proc_open). Those processes can be communicated with via stdin and stdout. Of course those processes can themselves be a php program. That is probably as close as you'll get.
You can have option of:
multi_curl
One can use system command for the same
Ideal scenario is, create a threading function in C language and compile/configure in PHP. Now that function will be the function of PHP.
How about pcntl_fork?
check our the manual page for examples: PHP pcntl_fork
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
If you are using a Linux server, you can use
exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")
If you need pass some args
exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")
In script.php
$args = $argv[1];
Or use Symfony
https://symfony.com/doc/current/components/process.html
$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);
$process->disableOutput();
$process->start();
Depending on what you're trying to do you could also use curl_multi to achieve it.
pcntl_fork won't work in a web server environment if it has safe mode turned on. In this case, it will only work in the CLI version of PHP.
I know this is an old question, but this will undoubtedly be useful to many: PHPThreads
Code Example:
function threadproc($thread, $param) {
echo "\tI'm a PHPThread. In this example, I was given only one parameter: \"". print_r($param, true) ."\" to work with, but I can accept as many as you'd like!\n";
for ($i = 0; $i < 10; $i++) {
usleep(1000000);
echo "\tPHPThread working, very busy...\n";
}
return "I'm a return value!";
}
$thread_id = phpthread_create($thread, array(), "threadproc", null, array("123456"));
echo "I'm the main thread doing very important work!\n";
for ($n = 0; $n < 5; $n++) {
usleep(1000000);
echo "Main thread...working!\n";
}
echo "\nMain thread done working. Waiting on our PHPThread...\n";
phpthread_join($thread_id, $retval);
echo "\n\nOur PHPThread returned: " . print_r($retval, true) . "!\n";
Requires PHP extensions:
posix
pcntl
sockets
I've been using this library in production now for months. I put a LOT of effort into making it feel like using POSIX pthreads. If you're comfortable with pthreads, you can pick this up and use it very effectively in no time.
Computationally, the inner workings are quite different, but practically, the functionality is nearly the same including semantics and syntax.
I've used it to write an extremely efficient WebSocket server that supports high throughput rates. Sorry, I'm rambling. I'm just excited that I finally got it released and I want to see who it will help!
popen()/proc_open() works parallel even in Windows.
Most often pitfall is "fread/stream_get_contents" without while loop. Once you try to fread() from running process it will block output for processes that run after it (cause of fread() waits until at least one byte arrives)
Add stream_select(). Closest analogy is "foreach with timeout but for streams", you pass few arrays to read and write and each call of stream_select() one or more streams will be selected. Function updates original arrays by reference, so dont forget to restore it to all streams before next call. Function gives them some time to read or write. If no content - control returns allowing us to retry cycle.
// sleep.php
set_error_handler(function ($severity, $error, $file, $line) {
throw new ErrorException($error, -1, $severity, $file, $line);
});
$sleep = $argv[ 1 ];
sleep($sleep);
echo $sleep . PHP_EOL;
exit(0);
// run.php
<?php
$procs = [];
$pipes = [];
$cmd = 'php %cd%/sleep.php';
$desc = [
0 => [ 'pipe', 'r' ],
1 => [ 'pipe', 'w' ],
2 => [ 'pipe', 'a' ],
];
for ( $i = 0; $i < 10; $i++ ) {
$iCmd = $cmd . ' ' . ( 10 - $i ); // add SLEEP argument to each command 10, 9, ... etc.
$proc = proc_open($iCmd, $desc, $pipes[ $i ], __DIR__);
$procs[ $i ] = $proc;
}
$stdins = array_column($pipes, 0);
$stdouts = array_column($pipes, 1);
$stderrs = array_column($pipes, 2);
while ( $procs ) {
foreach ( $procs as $i => $proc ) {
// #gzhegow > [OR] you can output while script is running (if child never finishes)
$read = [ $stdins[ $i ] ];
$write = [ $stdouts[ $i ], $stderrs[ $i ] ];
$except = [];
if (stream_select($read, $write, $except, $seconds = 0, $microseconds = 1000)) {
foreach ( $write as $stream ) {
echo stream_get_contents($stream);
}
}
$status = proc_get_status($proc);
if (false === $status[ 'running' ]) {
$status = proc_close($proc);
unset($procs[ $i ]);
echo 'STATUS: ' . $status . PHP_EOL;
}
// #gzhegow > [OR] you can output once command finishes
// $status = proc_get_status($proc);
//
// if (false === $status[ 'running' ]) {
// if ($content = stream_get_contents($stderrs[ $i ])) {
// echo '[ERROR]' . $content . PHP_EOL;
// }
//
// echo stream_get_contents($stdouts[ $i ]) . PHP_EOL;
//
// $status = proc_close($proc);
// unset($procs[ $i ]);
//
// echo 'STATUS: ' . $status . PHP_EOL;
// }
}
usleep(1); // give your computer one tick to decide what thread should be used
}
// ensure you receive 1,2,3... but you've just run it 10,9,8...
exit(0);
Multithreading means performing multiple tasks or processes simultaneously, we can achieve this in php by using following code,although there is no direct way to achieve multithreading in php but we can achieve almost same results by following way.
chdir(dirname(__FILE__)); //if you want to run this file as cron job
for ($i = 0; $i < 2; $i += 1){
exec("php test_1.php $i > test.txt &");
//this will execute test_1.php and will leave this process executing in the background and will go
//to next iteration of the loop immediately without waiting the completion of the script in the
//test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1]; //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert into test set
id='$i',
comment='test',
datetime=NOW() ");
}
This will execute test_1.php two times simultaneously and both process will run in the background simultaneously ,so in this way you can achieve multithreading in php.
This guy done really good work Multithreading in php
As of the writing of my current comment, I don't know about the PHP threads. I came to look for the answer here myself, but one workaround is that the PHP program that receives the request from the web server delegates the whole answer formulation to a console application that stores its output, the answer to the request, to a binary file and the PHP program that launched the console application returns that binary file byte-by-byte as the answer to the received request. The console application can be written in any programming language that runs on the server, including those that have proper threading support, including C++ programs that use OpenMP.
One unreliable, dirty, trick is to use PHP for executing a console application, "uname",
uname -a
and print the output of that console command to the HTML output to find out the exact version of the server software. Then install the exact same version of the software to a VirtualBox instance, compile/assemble whatever fully self-contained, preferably static, binaries that one wants and then upload those to the server. From that point onwards the PHP application can use those binaries in the role of the console application that has proper multi-threading. It's a dirty, unreliable, workaround to a situation, when the server administrator has not installed all needed programming language implementations to the server. The thing to watch out for is that at every request that the PHP application receives the console application(s) terminates/exit/get_killed.
As to what the hosting service administrators think of such server usage patterns, I guess it boils down to culture. In Northern Europe the service provider HAS TO DELIVER WHAT WAS ADVERTISED and if execution of console commands was allowed and uploading of non-malware files was allowed and the service provider has a right to kill any server process after a few minutes or even after 30 seconds, then the hosting service administrators lack any arguments for forming a proper complaint. In United States and Western Europe the situation/culture is very different and I believe that there's a great chance that in U.S. and/or Western Europe the hosting service provider will
refuse to serve hosting service clients that use the above described trick. That's just my guess, given my personal experience with U.S. hosting services and given what I have heard from others about Western European hosting services. As of the writing of my current comment(2018_09_01) I do not know anything about the cultural norms of the Southern-European hosting service providers, Southern-European network administrators.
Is there a realistic way of implementing a multi-threaded model in PHP whether truly, or just simulating it. Some time back it was suggested that you could force the operating system to load another instance of the PHP executable and handle other simultaneous processes.
The problem with this is that when the PHP code finished executing the PHP instance remains in memory because there is no way to kill it from within PHP. So if you are simulating several threads you can imagine whats going to happen. So I am still looking for a way multi-threading can be done or simulated effectively from within PHP. Any ideas?
Warning: This extension is considered unmaintained and dead.
Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP is therefore restricted to CLI-based applications only.
Warning: pthreads (v3) can only be used with PHP 7.2+: This is due to ZTS mode being unsafe in 7.0 and 7.1.
https://www.php.net/manual/en/intro.pthreads.php
Multi-threading is possible in php
Yes you can do multi-threading in PHP with pthreads
From the PHP documentation:
pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.
Warning:
The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.
Simple Test
#!/usr/bin/php
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = mt_rand(1, 10);
printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
sleep($sleep);
printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg);
}
}
}
// Create a array
$stack = array();
//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
$stack[] = new AsyncOperation($i);
}
// Start The Threads
foreach ( $stack as $t ) {
$t->start();
}
?>
First Run
12:00:06pm: A -start -sleeps 5
12:00:06pm: B -start -sleeps 3
12:00:06pm: C -start -sleeps 10
12:00:06pm: D -start -sleeps 2
12:00:08pm: D -finish
12:00:09pm: B -finish
12:00:11pm: A -finish
12:00:16pm: C -finish
Second Run
12:01:36pm: A -start -sleeps 6
12:01:36pm: B -start -sleeps 1
12:01:36pm: C -start -sleeps 2
12:01:36pm: D -start -sleeps 1
12:01:37pm: B -finish
12:01:37pm: D -finish
12:01:38pm: C -finish
12:01:42pm: A -finish
Real World Example
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if (($url = $this->url)) {
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents($url);
} else
printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
}
}
$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
printf("Request took %f seconds to start ", microtime(true) - $t);
while ( $g->isRunning() ) {
echo ".";
usleep(100);
}
if ($g->join()) {
printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
} else
printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
why don't you use popen?
for ($i=0; $i<10; $i++) {
// open ten processes
for ($j = 0; $j < 10; $j++) {
$pipe[$j] = popen('script2.php', 'w');
}
// wait for them to finish
for ($j = 0; $j < 10; ++$j) {
pclose($pipe[$j]);
}
}
Threading isn't available in stock PHP, but concurrent programming is possible by using HTTP requests as asynchronous calls.
With the curl's timeout setting set to 1 and using the same session_id for the processes you want to be associated with each other, you can communicate with session variables as in my example below. With this method you can even close your browser and the concurrent process still exists on the server.
Don't forget to verify the correct session ID like this:
http://localhost/test/verifysession.php?sessionid=[the correct id]
startprocess.php
$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];
process1.php
set_time_limit(0);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
function checkclose()
{
global $_SESSION;
if ($_SESSION["closesession"])
{
unset($_SESSION["closesession"]);
die();
}
}
while(!$close)
{
session_start();
$_SESSION["test"] = rand();
checkclose();
session_write_close();
sleep(5);
}
verifysession.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
closeprocess.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
While you can't thread, you do have some degree of process control in php. The two function sets that are useful here are:
Process control functions
http://www.php.net/manual/en/ref.pcntl.php
POSIX functions
http://www.php.net/manual/en/ref.posix.php
You could fork your process with pcntl_fork - returning the PID of the child. Then you can use posix_kill to despose of that PID.
That said, if you kill a parent process a signal should be sent to the child process telling it to die. If php itself isn't recognising this you could register a function to manage it and do a clean exit using pcntl_signal.
using threads is made possible by the pthreads PECL extension
http://www.php.net/manual/en/book.pthreads.php
I know this is an old question but for people searching, there is a PECL extension written in C that gives PHP multi-threading capability now, it's located here https://github.com/krakjoe/pthreads
You can use exec() to run a command line script (such as command line php), and if you pipe the output to a file then your script won't wait for the command to finish.
I can't quite remember the php CLI syntax, but you'd want something like:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
I think quite a few shared hosting servers have exec() disabled by default for security reasons, but might be worth a try.
You could simulate threading. PHP can run background processes via popen (or proc_open). Those processes can be communicated with via stdin and stdout. Of course those processes can themselves be a php program. That is probably as close as you'll get.
You can have option of:
multi_curl
One can use system command for the same
Ideal scenario is, create a threading function in C language and compile/configure in PHP. Now that function will be the function of PHP.
How about pcntl_fork?
check our the manual page for examples: PHP pcntl_fork
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
If you are using a Linux server, you can use
exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")
If you need pass some args
exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")
In script.php
$args = $argv[1];
Or use Symfony
https://symfony.com/doc/current/components/process.html
$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);
$process->disableOutput();
$process->start();
Depending on what you're trying to do you could also use curl_multi to achieve it.
pcntl_fork won't work in a web server environment if it has safe mode turned on. In this case, it will only work in the CLI version of PHP.
I know this is an old question, but this will undoubtedly be useful to many: PHPThreads
Code Example:
function threadproc($thread, $param) {
echo "\tI'm a PHPThread. In this example, I was given only one parameter: \"". print_r($param, true) ."\" to work with, but I can accept as many as you'd like!\n";
for ($i = 0; $i < 10; $i++) {
usleep(1000000);
echo "\tPHPThread working, very busy...\n";
}
return "I'm a return value!";
}
$thread_id = phpthread_create($thread, array(), "threadproc", null, array("123456"));
echo "I'm the main thread doing very important work!\n";
for ($n = 0; $n < 5; $n++) {
usleep(1000000);
echo "Main thread...working!\n";
}
echo "\nMain thread done working. Waiting on our PHPThread...\n";
phpthread_join($thread_id, $retval);
echo "\n\nOur PHPThread returned: " . print_r($retval, true) . "!\n";
Requires PHP extensions:
posix
pcntl
sockets
I've been using this library in production now for months. I put a LOT of effort into making it feel like using POSIX pthreads. If you're comfortable with pthreads, you can pick this up and use it very effectively in no time.
Computationally, the inner workings are quite different, but practically, the functionality is nearly the same including semantics and syntax.
I've used it to write an extremely efficient WebSocket server that supports high throughput rates. Sorry, I'm rambling. I'm just excited that I finally got it released and I want to see who it will help!
popen()/proc_open() works parallel even in Windows.
Most often pitfall is "fread/stream_get_contents" without while loop. Once you try to fread() from running process it will block output for processes that run after it (cause of fread() waits until at least one byte arrives)
Add stream_select(). Closest analogy is "foreach with timeout but for streams", you pass few arrays to read and write and each call of stream_select() one or more streams will be selected. Function updates original arrays by reference, so dont forget to restore it to all streams before next call. Function gives them some time to read or write. If no content - control returns allowing us to retry cycle.
// sleep.php
set_error_handler(function ($severity, $error, $file, $line) {
throw new ErrorException($error, -1, $severity, $file, $line);
});
$sleep = $argv[ 1 ];
sleep($sleep);
echo $sleep . PHP_EOL;
exit(0);
// run.php
<?php
$procs = [];
$pipes = [];
$cmd = 'php %cd%/sleep.php';
$desc = [
0 => [ 'pipe', 'r' ],
1 => [ 'pipe', 'w' ],
2 => [ 'pipe', 'a' ],
];
for ( $i = 0; $i < 10; $i++ ) {
$iCmd = $cmd . ' ' . ( 10 - $i ); // add SLEEP argument to each command 10, 9, ... etc.
$proc = proc_open($iCmd, $desc, $pipes[ $i ], __DIR__);
$procs[ $i ] = $proc;
}
$stdins = array_column($pipes, 0);
$stdouts = array_column($pipes, 1);
$stderrs = array_column($pipes, 2);
while ( $procs ) {
foreach ( $procs as $i => $proc ) {
// #gzhegow > [OR] you can output while script is running (if child never finishes)
$read = [ $stdins[ $i ] ];
$write = [ $stdouts[ $i ], $stderrs[ $i ] ];
$except = [];
if (stream_select($read, $write, $except, $seconds = 0, $microseconds = 1000)) {
foreach ( $write as $stream ) {
echo stream_get_contents($stream);
}
}
$status = proc_get_status($proc);
if (false === $status[ 'running' ]) {
$status = proc_close($proc);
unset($procs[ $i ]);
echo 'STATUS: ' . $status . PHP_EOL;
}
// #gzhegow > [OR] you can output once command finishes
// $status = proc_get_status($proc);
//
// if (false === $status[ 'running' ]) {
// if ($content = stream_get_contents($stderrs[ $i ])) {
// echo '[ERROR]' . $content . PHP_EOL;
// }
//
// echo stream_get_contents($stdouts[ $i ]) . PHP_EOL;
//
// $status = proc_close($proc);
// unset($procs[ $i ]);
//
// echo 'STATUS: ' . $status . PHP_EOL;
// }
}
usleep(1); // give your computer one tick to decide what thread should be used
}
// ensure you receive 1,2,3... but you've just run it 10,9,8...
exit(0);
Multithreading means performing multiple tasks or processes simultaneously, we can achieve this in php by using following code,although there is no direct way to achieve multithreading in php but we can achieve almost same results by following way.
chdir(dirname(__FILE__)); //if you want to run this file as cron job
for ($i = 0; $i < 2; $i += 1){
exec("php test_1.php $i > test.txt &");
//this will execute test_1.php and will leave this process executing in the background and will go
//to next iteration of the loop immediately without waiting the completion of the script in the
//test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1]; //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert into test set
id='$i',
comment='test',
datetime=NOW() ");
}
This will execute test_1.php two times simultaneously and both process will run in the background simultaneously ,so in this way you can achieve multithreading in php.
This guy done really good work Multithreading in php
As of the writing of my current comment, I don't know about the PHP threads. I came to look for the answer here myself, but one workaround is that the PHP program that receives the request from the web server delegates the whole answer formulation to a console application that stores its output, the answer to the request, to a binary file and the PHP program that launched the console application returns that binary file byte-by-byte as the answer to the received request. The console application can be written in any programming language that runs on the server, including those that have proper threading support, including C++ programs that use OpenMP.
One unreliable, dirty, trick is to use PHP for executing a console application, "uname",
uname -a
and print the output of that console command to the HTML output to find out the exact version of the server software. Then install the exact same version of the software to a VirtualBox instance, compile/assemble whatever fully self-contained, preferably static, binaries that one wants and then upload those to the server. From that point onwards the PHP application can use those binaries in the role of the console application that has proper multi-threading. It's a dirty, unreliable, workaround to a situation, when the server administrator has not installed all needed programming language implementations to the server. The thing to watch out for is that at every request that the PHP application receives the console application(s) terminates/exit/get_killed.
As to what the hosting service administrators think of such server usage patterns, I guess it boils down to culture. In Northern Europe the service provider HAS TO DELIVER WHAT WAS ADVERTISED and if execution of console commands was allowed and uploading of non-malware files was allowed and the service provider has a right to kill any server process after a few minutes or even after 30 seconds, then the hosting service administrators lack any arguments for forming a proper complaint. In United States and Western Europe the situation/culture is very different and I believe that there's a great chance that in U.S. and/or Western Europe the hosting service provider will
refuse to serve hosting service clients that use the above described trick. That's just my guess, given my personal experience with U.S. hosting services and given what I have heard from others about Western European hosting services. As of the writing of my current comment(2018_09_01) I do not know anything about the cultural norms of the Southern-European hosting service providers, Southern-European network administrators.
Is there a realistic way of implementing a multi-threaded model in PHP whether truly, or just simulating it. Some time back it was suggested that you could force the operating system to load another instance of the PHP executable and handle other simultaneous processes.
The problem with this is that when the PHP code finished executing the PHP instance remains in memory because there is no way to kill it from within PHP. So if you are simulating several threads you can imagine whats going to happen. So I am still looking for a way multi-threading can be done or simulated effectively from within PHP. Any ideas?
Warning: This extension is considered unmaintained and dead.
Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP is therefore restricted to CLI-based applications only.
Warning: pthreads (v3) can only be used with PHP 7.2+: This is due to ZTS mode being unsafe in 7.0 and 7.1.
https://www.php.net/manual/en/intro.pthreads.php
Multi-threading is possible in php
Yes you can do multi-threading in PHP with pthreads
From the PHP documentation:
pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.
Warning:
The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.
Simple Test
#!/usr/bin/php
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = mt_rand(1, 10);
printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
sleep($sleep);
printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg);
}
}
}
// Create a array
$stack = array();
//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
$stack[] = new AsyncOperation($i);
}
// Start The Threads
foreach ( $stack as $t ) {
$t->start();
}
?>
First Run
12:00:06pm: A -start -sleeps 5
12:00:06pm: B -start -sleeps 3
12:00:06pm: C -start -sleeps 10
12:00:06pm: D -start -sleeps 2
12:00:08pm: D -finish
12:00:09pm: B -finish
12:00:11pm: A -finish
12:00:16pm: C -finish
Second Run
12:01:36pm: A -start -sleeps 6
12:01:36pm: B -start -sleeps 1
12:01:36pm: C -start -sleeps 2
12:01:36pm: D -start -sleeps 1
12:01:37pm: B -finish
12:01:37pm: D -finish
12:01:38pm: C -finish
12:01:42pm: A -finish
Real World Example
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if (($url = $this->url)) {
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents($url);
} else
printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
}
}
$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
printf("Request took %f seconds to start ", microtime(true) - $t);
while ( $g->isRunning() ) {
echo ".";
usleep(100);
}
if ($g->join()) {
printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
} else
printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
why don't you use popen?
for ($i=0; $i<10; $i++) {
// open ten processes
for ($j = 0; $j < 10; $j++) {
$pipe[$j] = popen('script2.php', 'w');
}
// wait for them to finish
for ($j = 0; $j < 10; ++$j) {
pclose($pipe[$j]);
}
}
Threading isn't available in stock PHP, but concurrent programming is possible by using HTTP requests as asynchronous calls.
With the curl's timeout setting set to 1 and using the same session_id for the processes you want to be associated with each other, you can communicate with session variables as in my example below. With this method you can even close your browser and the concurrent process still exists on the server.
Don't forget to verify the correct session ID like this:
http://localhost/test/verifysession.php?sessionid=[the correct id]
startprocess.php
$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];
process1.php
set_time_limit(0);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
function checkclose()
{
global $_SESSION;
if ($_SESSION["closesession"])
{
unset($_SESSION["closesession"]);
die();
}
}
while(!$close)
{
session_start();
$_SESSION["test"] = rand();
checkclose();
session_write_close();
sleep(5);
}
verifysession.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
closeprocess.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
While you can't thread, you do have some degree of process control in php. The two function sets that are useful here are:
Process control functions
http://www.php.net/manual/en/ref.pcntl.php
POSIX functions
http://www.php.net/manual/en/ref.posix.php
You could fork your process with pcntl_fork - returning the PID of the child. Then you can use posix_kill to despose of that PID.
That said, if you kill a parent process a signal should be sent to the child process telling it to die. If php itself isn't recognising this you could register a function to manage it and do a clean exit using pcntl_signal.
using threads is made possible by the pthreads PECL extension
http://www.php.net/manual/en/book.pthreads.php
I know this is an old question but for people searching, there is a PECL extension written in C that gives PHP multi-threading capability now, it's located here https://github.com/krakjoe/pthreads
You can use exec() to run a command line script (such as command line php), and if you pipe the output to a file then your script won't wait for the command to finish.
I can't quite remember the php CLI syntax, but you'd want something like:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
I think quite a few shared hosting servers have exec() disabled by default for security reasons, but might be worth a try.
You could simulate threading. PHP can run background processes via popen (or proc_open). Those processes can be communicated with via stdin and stdout. Of course those processes can themselves be a php program. That is probably as close as you'll get.
You can have option of:
multi_curl
One can use system command for the same
Ideal scenario is, create a threading function in C language and compile/configure in PHP. Now that function will be the function of PHP.
How about pcntl_fork?
check our the manual page for examples: PHP pcntl_fork
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
If you are using a Linux server, you can use
exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")
If you need pass some args
exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")
In script.php
$args = $argv[1];
Or use Symfony
https://symfony.com/doc/current/components/process.html
$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);
$process->disableOutput();
$process->start();
Depending on what you're trying to do you could also use curl_multi to achieve it.
pcntl_fork won't work in a web server environment if it has safe mode turned on. In this case, it will only work in the CLI version of PHP.
I know this is an old question, but this will undoubtedly be useful to many: PHPThreads
Code Example:
function threadproc($thread, $param) {
echo "\tI'm a PHPThread. In this example, I was given only one parameter: \"". print_r($param, true) ."\" to work with, but I can accept as many as you'd like!\n";
for ($i = 0; $i < 10; $i++) {
usleep(1000000);
echo "\tPHPThread working, very busy...\n";
}
return "I'm a return value!";
}
$thread_id = phpthread_create($thread, array(), "threadproc", null, array("123456"));
echo "I'm the main thread doing very important work!\n";
for ($n = 0; $n < 5; $n++) {
usleep(1000000);
echo "Main thread...working!\n";
}
echo "\nMain thread done working. Waiting on our PHPThread...\n";
phpthread_join($thread_id, $retval);
echo "\n\nOur PHPThread returned: " . print_r($retval, true) . "!\n";
Requires PHP extensions:
posix
pcntl
sockets
I've been using this library in production now for months. I put a LOT of effort into making it feel like using POSIX pthreads. If you're comfortable with pthreads, you can pick this up and use it very effectively in no time.
Computationally, the inner workings are quite different, but practically, the functionality is nearly the same including semantics and syntax.
I've used it to write an extremely efficient WebSocket server that supports high throughput rates. Sorry, I'm rambling. I'm just excited that I finally got it released and I want to see who it will help!
popen()/proc_open() works parallel even in Windows.
Most often pitfall is "fread/stream_get_contents" without while loop. Once you try to fread() from running process it will block output for processes that run after it (cause of fread() waits until at least one byte arrives)
Add stream_select(). Closest analogy is "foreach with timeout but for streams", you pass few arrays to read and write and each call of stream_select() one or more streams will be selected. Function updates original arrays by reference, so dont forget to restore it to all streams before next call. Function gives them some time to read or write. If no content - control returns allowing us to retry cycle.
// sleep.php
set_error_handler(function ($severity, $error, $file, $line) {
throw new ErrorException($error, -1, $severity, $file, $line);
});
$sleep = $argv[ 1 ];
sleep($sleep);
echo $sleep . PHP_EOL;
exit(0);
// run.php
<?php
$procs = [];
$pipes = [];
$cmd = 'php %cd%/sleep.php';
$desc = [
0 => [ 'pipe', 'r' ],
1 => [ 'pipe', 'w' ],
2 => [ 'pipe', 'a' ],
];
for ( $i = 0; $i < 10; $i++ ) {
$iCmd = $cmd . ' ' . ( 10 - $i ); // add SLEEP argument to each command 10, 9, ... etc.
$proc = proc_open($iCmd, $desc, $pipes[ $i ], __DIR__);
$procs[ $i ] = $proc;
}
$stdins = array_column($pipes, 0);
$stdouts = array_column($pipes, 1);
$stderrs = array_column($pipes, 2);
while ( $procs ) {
foreach ( $procs as $i => $proc ) {
// #gzhegow > [OR] you can output while script is running (if child never finishes)
$read = [ $stdins[ $i ] ];
$write = [ $stdouts[ $i ], $stderrs[ $i ] ];
$except = [];
if (stream_select($read, $write, $except, $seconds = 0, $microseconds = 1000)) {
foreach ( $write as $stream ) {
echo stream_get_contents($stream);
}
}
$status = proc_get_status($proc);
if (false === $status[ 'running' ]) {
$status = proc_close($proc);
unset($procs[ $i ]);
echo 'STATUS: ' . $status . PHP_EOL;
}
// #gzhegow > [OR] you can output once command finishes
// $status = proc_get_status($proc);
//
// if (false === $status[ 'running' ]) {
// if ($content = stream_get_contents($stderrs[ $i ])) {
// echo '[ERROR]' . $content . PHP_EOL;
// }
//
// echo stream_get_contents($stdouts[ $i ]) . PHP_EOL;
//
// $status = proc_close($proc);
// unset($procs[ $i ]);
//
// echo 'STATUS: ' . $status . PHP_EOL;
// }
}
usleep(1); // give your computer one tick to decide what thread should be used
}
// ensure you receive 1,2,3... but you've just run it 10,9,8...
exit(0);
Multithreading means performing multiple tasks or processes simultaneously, we can achieve this in php by using following code,although there is no direct way to achieve multithreading in php but we can achieve almost same results by following way.
chdir(dirname(__FILE__)); //if you want to run this file as cron job
for ($i = 0; $i < 2; $i += 1){
exec("php test_1.php $i > test.txt &");
//this will execute test_1.php and will leave this process executing in the background and will go
//to next iteration of the loop immediately without waiting the completion of the script in the
//test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1]; //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert into test set
id='$i',
comment='test',
datetime=NOW() ");
}
This will execute test_1.php two times simultaneously and both process will run in the background simultaneously ,so in this way you can achieve multithreading in php.
This guy done really good work Multithreading in php
As of the writing of my current comment, I don't know about the PHP threads. I came to look for the answer here myself, but one workaround is that the PHP program that receives the request from the web server delegates the whole answer formulation to a console application that stores its output, the answer to the request, to a binary file and the PHP program that launched the console application returns that binary file byte-by-byte as the answer to the received request. The console application can be written in any programming language that runs on the server, including those that have proper threading support, including C++ programs that use OpenMP.
One unreliable, dirty, trick is to use PHP for executing a console application, "uname",
uname -a
and print the output of that console command to the HTML output to find out the exact version of the server software. Then install the exact same version of the software to a VirtualBox instance, compile/assemble whatever fully self-contained, preferably static, binaries that one wants and then upload those to the server. From that point onwards the PHP application can use those binaries in the role of the console application that has proper multi-threading. It's a dirty, unreliable, workaround to a situation, when the server administrator has not installed all needed programming language implementations to the server. The thing to watch out for is that at every request that the PHP application receives the console application(s) terminates/exit/get_killed.
As to what the hosting service administrators think of such server usage patterns, I guess it boils down to culture. In Northern Europe the service provider HAS TO DELIVER WHAT WAS ADVERTISED and if execution of console commands was allowed and uploading of non-malware files was allowed and the service provider has a right to kill any server process after a few minutes or even after 30 seconds, then the hosting service administrators lack any arguments for forming a proper complaint. In United States and Western Europe the situation/culture is very different and I believe that there's a great chance that in U.S. and/or Western Europe the hosting service provider will
refuse to serve hosting service clients that use the above described trick. That's just my guess, given my personal experience with U.S. hosting services and given what I have heard from others about Western European hosting services. As of the writing of my current comment(2018_09_01) I do not know anything about the cultural norms of the Southern-European hosting service providers, Southern-European network administrators.
EDIT: I've tagged this C in a hope to get more response. It's more the theory I'm interested in than a specific language implementation. So if you're a C coder please treat the following PHP as pseudo-code and feel free to respond with an answer written in C.
I am trying to speed up a PHP CLI script by having it execute its tasks in parallel instead of serial. The tasks are completely independent of each other so it doesn't matter which order they start/finish in.
Here's the original script (note all these examples are stripped-back for clarity):
<?php
$items = range(0, 100);
function do_stuff_with($item) { echo "$item\n"; }
foreach ($items as $item) {
do_stuff_with($item);
}
I've managed to make it work on the $items in parallel with pcntl_fork() as shown below:
<?php
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$items = range(0, 100);
function do_stuff_with($item) { echo "$item\n"; }
$pids = array();
foreach ($items as $item) {
$pid = pcntl_fork();
if ($pid == -1) {
die("couldn't fork()");
} elseif ($pid > 0) {
// parent
$pids[] = $pid;
} else {
// child
do_stuff_with($item);
exit(0);
}
}
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
Now I want to extend this so there's a maximum of, say, 10 children active at once. What's the best way of handling this? I've tried a few things but haven't had much luck.
There is no syscall to get a list of child pids, but ps can do it for you.
--ppid switch will list all children for you process so you just need to count number of lines outputted by ps.
Alternatively you can maintain your own counter that you will increment on fork() and decrement on SIGCHLD signal, assuming ppid stays unchanged for fork'ed processed.
The best thing I can come up with is to add all the tasks to a queue, launch the maximum number of threads you want, and then have each thread requesting a task from the queue, execute the task and requesting the next one. Don't forget to have the threads terminate when there are no more tasks to do.
Forking is an expensive operation. From the looks of it, what you really want is multithreading, not multiprocessing. The difference is that threads are much lighter weight than processes, since threads share a virtual address space but processes have separate virtual address spaces.
I'm not a PHP developer, but a quick Google search reveals that PHP does not support multithreading natively, but there are libraries to do the job.
Anyways, once you figure out how to spawn threads, you should figure out how many threads to spawn. In order to do this, you need to know what the bottleneck of your application is. Is the bottleneck CPU, memory, or I/O? You've indicated in your comments that you are network-bound, and network is a type of I/O.
If you were CPU bound, you're only going to get as much parallelism as you have CPU cores; any more threads and you're just wasting time doing context switches. Assuming you can figure out how many total threads to spawn, you should divide your work into that many units, and have each thread process one unit independently.
If you were memory bound, then multithreading would not help.
Since you're I/O bound, figuring out how many threads to spawn is a little trickier. If all work items take approximately the same time to process with very low variance, you can estimate how many threads to spawn by measuring how long one work item takes. However, since network packets tend to have highly variable latencies, this is unlikely to be the case.
One option is to use thread pools - you create a whole bunch of threads, and then for each item to process, you see if there is a free thread in the pool. If there is, you have that thread perform the work, and you move onto the next item. Otherwise, you wait for a thread to become available. Choosing the size of the thread pool is important - too big, and you're wasting time doing unnecessary context switches. Too few, and you're waiting for threads too often.
Yet another option is to abandon multithreading/multiprocessing and just do asynchronous I/O instead. Since you mentioned you're working on a single-core processor, this will probably be the fastest option. You can use functions like socket_select() to test if a socket has data available. If it does, you can read the data, otherwise you move onto a different socket. This requires doing a lot more bookkeeping, but you avoid waiting for data to come in on one socket when data is available on a different socket.
If you want to eschew threads and asynchronous I/O and stick with multiprocessing, it can still be worthwhile if the per-item processing is expensive enough. You might then do the work division like so:
$my_process_index = 0;
$pids = array();
// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
$pid = pcntl_fork();
if($pid == -1)
{
die("couldn't fork()");
}
elseif($pid > 0)
{
// parent
$my_process_index++;
$pids[] = $pid
}
else
{
// child
break;
}
}
// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
do_stuff_with($items[$i]);
}
if($my_process_index != 0)
{
exit(0);
}
man 2 setrlimit
That's going to be per-user which may be what you want anyway.
<?php
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$items = range(0, 100);
function do_stuff_with($item) { echo "$item\n"; }
$pids = array();
while (count($items)){
$item = array_pop($items);
$pid = pcntl_fork();
if ($pid == -1) {
die("couldn't fork()");
} elseif ($pid > 0) {
// parent
$pids[] = $pid;
} else {
// child
do_stuff_with($item);
exit(0);
}
while (count($pids) >= 10){ // limit
while (($wait_pid = pcntl_waitpid(0, $status)) != -1) {
$status = pcntl_wexitstatus($status);
array_pop($pids);
echo "$wait_pid $status".PHP_EOL;
break;
}
}
}
while (count($pids)){
while (($wait_pid = pcntl_waitpid(0, $status)) != -1) {
$status = pcntl_wexitstatus($status);
array_pop($pids);
echo "CHILD: child $status completed $wait_pid".PHP_EOL;
break;
}
}
Is there a realistic way of implementing a multi-threaded model in PHP whether truly, or just simulating it. Some time back it was suggested that you could force the operating system to load another instance of the PHP executable and handle other simultaneous processes.
The problem with this is that when the PHP code finished executing the PHP instance remains in memory because there is no way to kill it from within PHP. So if you are simulating several threads you can imagine whats going to happen. So I am still looking for a way multi-threading can be done or simulated effectively from within PHP. Any ideas?
Warning: This extension is considered unmaintained and dead.
Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP is therefore restricted to CLI-based applications only.
Warning: pthreads (v3) can only be used with PHP 7.2+: This is due to ZTS mode being unsafe in 7.0 and 7.1.
https://www.php.net/manual/en/intro.pthreads.php
Multi-threading is possible in php
Yes you can do multi-threading in PHP with pthreads
From the PHP documentation:
pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.
Warning:
The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.
Simple Test
#!/usr/bin/php
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = mt_rand(1, 10);
printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
sleep($sleep);
printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg);
}
}
}
// Create a array
$stack = array();
//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
$stack[] = new AsyncOperation($i);
}
// Start The Threads
foreach ( $stack as $t ) {
$t->start();
}
?>
First Run
12:00:06pm: A -start -sleeps 5
12:00:06pm: B -start -sleeps 3
12:00:06pm: C -start -sleeps 10
12:00:06pm: D -start -sleeps 2
12:00:08pm: D -finish
12:00:09pm: B -finish
12:00:11pm: A -finish
12:00:16pm: C -finish
Second Run
12:01:36pm: A -start -sleeps 6
12:01:36pm: B -start -sleeps 1
12:01:36pm: C -start -sleeps 2
12:01:36pm: D -start -sleeps 1
12:01:37pm: B -finish
12:01:37pm: D -finish
12:01:38pm: C -finish
12:01:42pm: A -finish
Real World Example
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if (($url = $this->url)) {
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents($url);
} else
printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
}
}
$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
printf("Request took %f seconds to start ", microtime(true) - $t);
while ( $g->isRunning() ) {
echo ".";
usleep(100);
}
if ($g->join()) {
printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
} else
printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
why don't you use popen?
for ($i=0; $i<10; $i++) {
// open ten processes
for ($j = 0; $j < 10; $j++) {
$pipe[$j] = popen('script2.php', 'w');
}
// wait for them to finish
for ($j = 0; $j < 10; ++$j) {
pclose($pipe[$j]);
}
}
Threading isn't available in stock PHP, but concurrent programming is possible by using HTTP requests as asynchronous calls.
With the curl's timeout setting set to 1 and using the same session_id for the processes you want to be associated with each other, you can communicate with session variables as in my example below. With this method you can even close your browser and the concurrent process still exists on the server.
Don't forget to verify the correct session ID like this:
http://localhost/test/verifysession.php?sessionid=[the correct id]
startprocess.php
$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];
process1.php
set_time_limit(0);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
function checkclose()
{
global $_SESSION;
if ($_SESSION["closesession"])
{
unset($_SESSION["closesession"]);
die();
}
}
while(!$close)
{
session_start();
$_SESSION["test"] = rand();
checkclose();
session_write_close();
sleep(5);
}
verifysession.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
closeprocess.php
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
While you can't thread, you do have some degree of process control in php. The two function sets that are useful here are:
Process control functions
http://www.php.net/manual/en/ref.pcntl.php
POSIX functions
http://www.php.net/manual/en/ref.posix.php
You could fork your process with pcntl_fork - returning the PID of the child. Then you can use posix_kill to despose of that PID.
That said, if you kill a parent process a signal should be sent to the child process telling it to die. If php itself isn't recognising this you could register a function to manage it and do a clean exit using pcntl_signal.
using threads is made possible by the pthreads PECL extension
http://www.php.net/manual/en/book.pthreads.php
I know this is an old question but for people searching, there is a PECL extension written in C that gives PHP multi-threading capability now, it's located here https://github.com/krakjoe/pthreads
You can use exec() to run a command line script (such as command line php), and if you pipe the output to a file then your script won't wait for the command to finish.
I can't quite remember the php CLI syntax, but you'd want something like:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
I think quite a few shared hosting servers have exec() disabled by default for security reasons, but might be worth a try.
You could simulate threading. PHP can run background processes via popen (or proc_open). Those processes can be communicated with via stdin and stdout. Of course those processes can themselves be a php program. That is probably as close as you'll get.
You can have option of:
multi_curl
One can use system command for the same
Ideal scenario is, create a threading function in C language and compile/configure in PHP. Now that function will be the function of PHP.
How about pcntl_fork?
check our the manual page for examples: PHP pcntl_fork
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
If you are using a Linux server, you can use
exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")
If you need pass some args
exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")
In script.php
$args = $argv[1];
Or use Symfony
https://symfony.com/doc/current/components/process.html
$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);
$process->disableOutput();
$process->start();
Depending on what you're trying to do you could also use curl_multi to achieve it.
pcntl_fork won't work in a web server environment if it has safe mode turned on. In this case, it will only work in the CLI version of PHP.
I know this is an old question, but this will undoubtedly be useful to many: PHPThreads
Code Example:
function threadproc($thread, $param) {
echo "\tI'm a PHPThread. In this example, I was given only one parameter: \"". print_r($param, true) ."\" to work with, but I can accept as many as you'd like!\n";
for ($i = 0; $i < 10; $i++) {
usleep(1000000);
echo "\tPHPThread working, very busy...\n";
}
return "I'm a return value!";
}
$thread_id = phpthread_create($thread, array(), "threadproc", null, array("123456"));
echo "I'm the main thread doing very important work!\n";
for ($n = 0; $n < 5; $n++) {
usleep(1000000);
echo "Main thread...working!\n";
}
echo "\nMain thread done working. Waiting on our PHPThread...\n";
phpthread_join($thread_id, $retval);
echo "\n\nOur PHPThread returned: " . print_r($retval, true) . "!\n";
Requires PHP extensions:
posix
pcntl
sockets
I've been using this library in production now for months. I put a LOT of effort into making it feel like using POSIX pthreads. If you're comfortable with pthreads, you can pick this up and use it very effectively in no time.
Computationally, the inner workings are quite different, but practically, the functionality is nearly the same including semantics and syntax.
I've used it to write an extremely efficient WebSocket server that supports high throughput rates. Sorry, I'm rambling. I'm just excited that I finally got it released and I want to see who it will help!
popen()/proc_open() works parallel even in Windows.
Most often pitfall is "fread/stream_get_contents" without while loop. Once you try to fread() from running process it will block output for processes that run after it (cause of fread() waits until at least one byte arrives)
Add stream_select(). Closest analogy is "foreach with timeout but for streams", you pass few arrays to read and write and each call of stream_select() one or more streams will be selected. Function updates original arrays by reference, so dont forget to restore it to all streams before next call. Function gives them some time to read or write. If no content - control returns allowing us to retry cycle.
// sleep.php
set_error_handler(function ($severity, $error, $file, $line) {
throw new ErrorException($error, -1, $severity, $file, $line);
});
$sleep = $argv[ 1 ];
sleep($sleep);
echo $sleep . PHP_EOL;
exit(0);
// run.php
<?php
$procs = [];
$pipes = [];
$cmd = 'php %cd%/sleep.php';
$desc = [
0 => [ 'pipe', 'r' ],
1 => [ 'pipe', 'w' ],
2 => [ 'pipe', 'a' ],
];
for ( $i = 0; $i < 10; $i++ ) {
$iCmd = $cmd . ' ' . ( 10 - $i ); // add SLEEP argument to each command 10, 9, ... etc.
$proc = proc_open($iCmd, $desc, $pipes[ $i ], __DIR__);
$procs[ $i ] = $proc;
}
$stdins = array_column($pipes, 0);
$stdouts = array_column($pipes, 1);
$stderrs = array_column($pipes, 2);
while ( $procs ) {
foreach ( $procs as $i => $proc ) {
// #gzhegow > [OR] you can output while script is running (if child never finishes)
$read = [ $stdins[ $i ] ];
$write = [ $stdouts[ $i ], $stderrs[ $i ] ];
$except = [];
if (stream_select($read, $write, $except, $seconds = 0, $microseconds = 1000)) {
foreach ( $write as $stream ) {
echo stream_get_contents($stream);
}
}
$status = proc_get_status($proc);
if (false === $status[ 'running' ]) {
$status = proc_close($proc);
unset($procs[ $i ]);
echo 'STATUS: ' . $status . PHP_EOL;
}
// #gzhegow > [OR] you can output once command finishes
// $status = proc_get_status($proc);
//
// if (false === $status[ 'running' ]) {
// if ($content = stream_get_contents($stderrs[ $i ])) {
// echo '[ERROR]' . $content . PHP_EOL;
// }
//
// echo stream_get_contents($stdouts[ $i ]) . PHP_EOL;
//
// $status = proc_close($proc);
// unset($procs[ $i ]);
//
// echo 'STATUS: ' . $status . PHP_EOL;
// }
}
usleep(1); // give your computer one tick to decide what thread should be used
}
// ensure you receive 1,2,3... but you've just run it 10,9,8...
exit(0);
Multithreading means performing multiple tasks or processes simultaneously, we can achieve this in php by using following code,although there is no direct way to achieve multithreading in php but we can achieve almost same results by following way.
chdir(dirname(__FILE__)); //if you want to run this file as cron job
for ($i = 0; $i < 2; $i += 1){
exec("php test_1.php $i > test.txt &");
//this will execute test_1.php and will leave this process executing in the background and will go
//to next iteration of the loop immediately without waiting the completion of the script in the
//test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1]; //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert into test set
id='$i',
comment='test',
datetime=NOW() ");
}
This will execute test_1.php two times simultaneously and both process will run in the background simultaneously ,so in this way you can achieve multithreading in php.
This guy done really good work Multithreading in php
As of the writing of my current comment, I don't know about the PHP threads. I came to look for the answer here myself, but one workaround is that the PHP program that receives the request from the web server delegates the whole answer formulation to a console application that stores its output, the answer to the request, to a binary file and the PHP program that launched the console application returns that binary file byte-by-byte as the answer to the received request. The console application can be written in any programming language that runs on the server, including those that have proper threading support, including C++ programs that use OpenMP.
One unreliable, dirty, trick is to use PHP for executing a console application, "uname",
uname -a
and print the output of that console command to the HTML output to find out the exact version of the server software. Then install the exact same version of the software to a VirtualBox instance, compile/assemble whatever fully self-contained, preferably static, binaries that one wants and then upload those to the server. From that point onwards the PHP application can use those binaries in the role of the console application that has proper multi-threading. It's a dirty, unreliable, workaround to a situation, when the server administrator has not installed all needed programming language implementations to the server. The thing to watch out for is that at every request that the PHP application receives the console application(s) terminates/exit/get_killed.
As to what the hosting service administrators think of such server usage patterns, I guess it boils down to culture. In Northern Europe the service provider HAS TO DELIVER WHAT WAS ADVERTISED and if execution of console commands was allowed and uploading of non-malware files was allowed and the service provider has a right to kill any server process after a few minutes or even after 30 seconds, then the hosting service administrators lack any arguments for forming a proper complaint. In United States and Western Europe the situation/culture is very different and I believe that there's a great chance that in U.S. and/or Western Europe the hosting service provider will
refuse to serve hosting service clients that use the above described trick. That's just my guess, given my personal experience with U.S. hosting services and given what I have heard from others about Western European hosting services. As of the writing of my current comment(2018_09_01) I do not know anything about the cultural norms of the Southern-European hosting service providers, Southern-European network administrators.