Wednesday, August 26, 2009

PHP Multithreading for beginner

This entry is inspired by Iman "Sapi". Thank you sapi.

PHP has become not just web scripting language. Now PHP also widely use for simple server side shell scripting. PHP is proven a strong platform do perform database and www operation, such as querying, CURL-ing, http tunnelling and API's function.


The differences is at output and how long the script allowed to runs. Output of web-based PHP mostly markup languages bounded with fancy images and media files. But shell scripting only output only-God-knows log messages, and has no time limit.


Supported by enormous of active developer, PHP server scripting are very easy to those actively build applications under web. PHP also powerful to build heavy-duty task, such as file backup, backend server-to-server processes. Like Java, PHP5 now has the capability for multithreading, to increase processing speed. The only limit is memory and processor. But I found for doing certain task (my case) it's much lighter than using Java.

To enable, first make sure you've installed pcntl extension. On Ubuntu machine, install the extension files :
$ sudo apt-get install php5-dev
$ cd ~
$ mkdir php-temp
$ cd php-temp
$ sudo apt-get source php5
$ cd php5-xx.xx/ext/pcntl (xx.xx is your PHP5 subversion, pressing tab would reveal it)
$ sudo phpize
$ sudo ./configure
$ sudo make

Copy the compiled extension into modules library.
$ cp modules/* /usr/lib/php5/xxxxxx/ (xxxxx is php library date)

Restart apache
$ sudo /etc/init.d/apache2 restart


Next is, try copy and paste this simple script simulate the multithreading.
Further reading, please visit PHP official manual page. Happy multi-threading.



$children = 5;

for ($i=1; $i<=$children; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
SaveLog("THREADING","could not fork thread $i");
die("could not fork\n");
}
else if ($pid) {
# If we are the parent, we did our job of giving birth,
# now lets finish our job and die!
SaveLog("THREADING","Parent thread exiting..");
exit(0);
}
else {
# Since we are the child, fork so that init will become our parent. Init
# is good at wait()ing on children - ie: reaping.
$cpid = pcntl_fork();
if ($cpid == -1) {
SaveLog("THREADING","could not fork in child process $i");
die("could not fork in child process\n");
}
if (!$cpid) {
# Put your real task here, dont forget they're run as separate process, make sure no dependency each thread
SaveLog("THREADING","Thread $i started");
$result = StupidTask(10000000);
SaveLog("TASK","Result on thread $i : $result");
SaveLog("THREADING","Thread $i finished");
# Don't forget to exit after the child processing is done. Certainly
# change this exit code if you need to however.
exit(0);
}
}
}

function StupidTask($count) {
for ($i=1;$i<$count;$i++) {
}
return "I'm done doing stupid thing for $count times";
}

function SaveLog($type,$msg) {
global $logfile;
file_put_contents($logfile,date('Y-m-d H:i:s') . ' ' . $type . ' ' . $msg . "\n",FILE_APPEND);
return true;
}

No comments: