php多進程的實現依賴於pcntl擴充,編譯PHP的時候,可以加上’–enable-pcntl’或者也可以單獨編譯。
有三點需要注意:
1.子進程不在執行fork之前的代碼,只是把父進程的記憶體狀況複製一份新的,所以,關於子進程的個人化需要單獨設定。
2.輸出重新導向,程式中使用echo,或造成命令列的混亂,影響分辨。可以用ob_start重新導向到log檔案,當然,你直接使用log是更好的辦法。此執行個體中log檔案,按照進程pid分組。
3.父進程沒有代碼執行,將可能提前退出,子進程可能成為孤兒進程。
demo接受:
用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(); } |
多進程式控制制的架構代碼,留著備查
| 代碼如下 |
複製代碼 |
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; |
例子
給出一段PHP多線程、與For迴圈,抓取百度搜尋網頁面的PHP程式碼範例:
| 代碼如下 |
複製代碼 |
<?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"; ?> |
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),www.111cn.net 編輯參數 --enable-maintainer-zts 是必選項:
| 代碼如下 |
複製代碼 |
cd /Data/tgz/php-5.5.1 ./configure --prefix=/Data/apps/php --with-config-file-path=/Data/apps/php/etc --with-mysql=/Data/apps/mysql --with-mysqli=/Data/apps/mysql/bin/mysql_config --with-iconv-dir --with-freetype-dir=/Data/apps/libs --with-jpeg-dir=/Data/apps/libs --with-png-dir=/Data/apps/libs --with-zlib --with-libxml-dir=/usr --enable-xml --disable-rpath --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --with-curl --enable-mbregex --enable-fpm --enable-mbstring --with-mcrypt=/Data/apps/libs --with-gd --enable-gd-native-ttf --with-openssl --with-mhash --enable-pcntl --enable-sockets --with-xmlrpc --enable-zip --enable-soap --enable-opcache --with-pdo-mysql --enable-maintainer-zts make clean make make install unzip pthreads-master.zip cd pthreads-master /Data/apps/php/bin/phpize ./configure --with-php-config=/Data/apps/php/bin/php-config make make install vi /Data/apps/php/etc/php.ini
|
添加:
| 代碼如下 |
複製代碼 |
| extension = "pthreads.so" |
PHP擴充下載:https://github.com/krakjoe/pthreads
PHP手冊文檔:http://php.net/manual/zh/book.pthreads.php