几个关于php多进程的例子
php多进程的实现依赖于pcntl扩展,编译php时,可以加上’–enable-pcntl’或者也可以单独编译。
注意:
1、子进程不在执行fork之前的代码,只是把父进程的内存状况复制一份新的,所以,关于子进程的个性化设置需要单独设置。
2、输出重定向,程序中使用echo,或造成命令行的混乱,影响分辨。可以用ob_start重定向到log文件,当然直接使用log是更好的办法。
此实例中log文件,按照进程pid分组。
3、父进程没有代码执行,将可能提前退出,子进程可能成为孤儿进程。
用10个子进程来处理输出任务,任务总量是1000,然后,按照任务数平均分到十个子进程当中去。
例子:
<?php
//输出重定向到log文件
function echo_to_log($content){
global $current_pid;
$logfile = __FILE__ . $current_pid . '.log';
$fp = fopen($logfile, 'a+');
fwrite($fp, $content);
fclose($fp);
}
ob_start('echo_to_log');
//获取当前进程pid
$current_pid = getmypid();
$fork_nums = 10;
$total = 1000;
for($i = 0; $i < $fork_nums; $i++){
$pid = pcntl_fork();
//等于0时,是子进程
if($pid == 0){
$current_pid = $pid;
do_task($i);
//大于0时,是父进程,并且pid是产生的子进程的PID
} else if($pid > 0) {
}
}
//任务函数
function do_task($task_num){
global $total;
$start = $total / 10 * $task_num;
$end = $total / 10 * ($task_num + 1);
for(;$start<$end;$start++){
echo $task_num . " " . $start . "\n";
}
//子进程执行完任务以后终止,当然你可以返回主进程的代码部分做相关操作。
exit();
}
例2,多进程控制的框架代码,留着备查。
declare(ticks=1);
function sigHandler($signal)
{
echo "a child exited\n";
}
pcntl_signal(SIGCHLD, sigHandler, false);
echo "this is " . posix_getpid() . PHP_EOL;
for($i=0; $i<3; $i++)
{
$pid = pcntl_fork();
if($pid == -1)
{
echo 'fork failed ' . PHP_EOL;
}
else if($pid)
{
}
else
{
$pid = posix_getpid();
echo 'child ' . $pid . ' ' . time() . PHP_EOL;
sleep(rand(2,5));
echo 'child ' . $pid . ' done ' . time() . PHP_EOL;
exit(0);
}
}
do
{
$pid = pcntl_wait($status);
echo 'child quit ' . $pid . PHP_EOL;
}while($pid > 0);
echo 'parent done' . PHP_EOL;
例3,PHP多线程、与For循环,抓取百度搜索页面。
<?php
class test_thread_run extends Thread
{
public $url;
public $data;
public function __construct($url)
{
$this->url = $url;
}
public function run()
{
if(($url = $this->url))
{
$this->data = model_http_curl_get($url);
}
}
}
function model_thread_result_get($urls_array)
{
foreach ($urls_array as $key => $value)
{
$thread_array[$key] = new test_thread_run($value["url"]);
$thread_array[$key]->start();
}
foreach ($thread_array as $thread_array_key => $thread_array_value)
{
while($thread_array[$thread_array_key]->isRunning())
{
usleep(10);
}
if($thread_array[$thread_array_key]->join())
{
$variable_data[$thread_array_key] = $thread_array[$thread_array_key]->data;
}
}
return $variable_data;
}
function model_http_curl_get($url,$userAgent="")
{
$userAgent = $userAgent ? $userAgent : 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
curl_setopt($curl, CURLOPT_USERAGENT, $userAgent);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
for ($i=0; $i < 100; $i++)
{
$urls_array[] = array("name" => "baidu", "url" => "http://www.baidu.com/s?wd=".mt_rand(10000,20000));
}
$t = microtime(true);
$result = model_thread_result_get($urls_array);
$e = microtime(true);
echo "多线程:".($e-$t)."\n";
$t = microtime(true);
foreach ($urls_array as $key => $value)
{
$result_new[$key] = model_http_curl_get($value["url"]);
}
$e = microtime(true);
echo "For循环:".($e-$t)."\n";
?>
例4,php多线程类:
/** * @title: PHP多线程类(Thread) * @version: 1.0 * @author: < web@ > * @published: 2010-11-2 * * PHP多线程应用示例: * require_once 'thread.class.php'; * $thread = new thread(); * $thread->addthread('action_log','a'); * $thread->addthread('action_log','b'); * $thread->addthread('action_log','c'); * $thread->runthread(); * * function action_log($info) { * $log = 'log/' . microtime() . '.log'; * $txt = $info . "rnrn" . 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn"; * $fp = fopen($log, 'w'); * fwrite($fp, $txt); * fclose($fp); * } */ class thread { var $hooks = array(); var $args = array(); function thread() { } function addthread($func) { $args = array_slice(func_get_args(), 1); $this->hooks[] = $func; $this->args[] = $args; return true; } function runthread() { if(isset($_GET['flag'])) { $flag = intval($_GET['flag']); } if($flag || $flag === 0) { call_user_func_array($this->hooks[$flag], $this->args[$flag]); } else { for($i = 0, $size = count($this->hooks); $i < $size; $i++) { $fp=fsockopen($_SERVER['HTTP_HOST'],$_SERVER['SERVER_PORT']); if($fp) { $out = "GET {$_SERVER['PHP_SELF']}?flag=$i HTTP/1.1rn"; $out .= "Host: {$_SERVER['HTTP_HOST']}rn"; $out .= "Connection: Closernrn"; fputs($fp,$out); fclose($fp); } } } } }
使用方法:
$thread = new thread();
$thread->addthread('func1','info1');
$thread->addthread('func2','info2');
$thread->addthread('func3','info3');
$thread->runthread();
说明:
addthread是添加线程函数,第一个参数是函数名,之后的参数(可选)为传递给指定函数的参数。
runthread是执行线程的函数。
在linux系统中配置安装下pthreads:
1、扩展的编译安装(Linux),编辑参数 --enable-maintainer-zts 是必选项:
vi /Data/apps/php/etc/php.ini
添加:
extension = "pthreads.so"