PHP 如何实现异步?

对于在短时间内需要重复执行某一简单功能的系统而言,异步是优化性能的必经之路。

实现异步的方式有两种:

1、模拟 HTTP 请求,这种方式每次都要经过三次握手,更适用于不同服务器之间的异步请求。

2、通过 CLI 与操作系统交互来实现。

一、模拟 HTTP 请求,每次执行的请求较慢,但因为异步,性能也会有极大的优化。

HTTP协议维基百科:http://zh.wikipedia.org/wiki/超文本传输协议

模拟 HTTP 请求有两种方式:CURL 与 SOCKET

CURL 实例如下:

\(handle = curl_init(); curl_setopt(\)handle, CURLOPT_URL, 'http://www.ifeng.com');

curl_setopt(\(handle, CURLOPT_HEADER, false); curl_setopt(\)handle, CURLOPT_BINARYTRANSFER, true);

curl_setopt(\(handle, CURLOPT_RETURNTRANSFER, true); \)content = curl_exec(\(handle); var_dump(\)content);

CURL 可模拟所有的浏览器操作,也可进行加密传输。

socket 实例如下:

\(host = 'www.ifeng.com'; \)path = '/index.shtml';

$params = 'a=1&b=2&c=3';

\(errorNo = null; \)errorMessage = '';

$timeOut = 30;

\(fp = @fsockopen(\)host, 80, $errorNo, $errorMessage, \(timeOut); if(!\)fp) {

exit('scoket 创建失败:'.$errorMessage);

}

\(request = ''; \)request .= "POST ".\(path." HTTP/1.1\r\n"; \)request .= "Host: ".\(host."\r\n"; \)request .= "Connection: Close\r\n";

\(request .= "Content-Type: application/x-www-form-urlencoded\r\n"; \)request .= "Content-length: ".strlen(\(params)."\r\n\r\n"; \)request .= $params;

fputs($fp, \(request); \)response = '';

while(!feof(\(fp)) { \)response .= fgets(\(fp, 128); } fclose(\)fp);

二、通过 CLI 在命令行与操作系统进行交互,此种方式只适用于请求自己系统的资源

通过 CLI 也有多种实现方式,大致分为两类:异步与多进程

异步与多进程在原理上是一致的,都是让操作系统产生新的进程。

异步在于进程产生,执行完成后即消息,无法获知进程的状态。

多进程在于可以获取进程执行的状态,并控制杀死产生的子进程。

PHP没有自带的多进程处理机制,只能通过扩展来实现,如:pcntl 扩展

PHP 可以通过 exec,system,passthru,popen 等方式来实现。

PCNTL 实例如下:

$pid = pcntl_fork();

//echo \(pid."<br/>"; if(\)pid == -1) {

exit('创建进程出错');

} elseif(\(pid) { exit('这里是父进程'); } else { //这里可以不用异步 \)phpShell = '/usr/local/php5.3/bin/php -f ';

\(phpFile = 'process.php'; \)processes = array();

for($i = 0; $i < 500; \(i++) { system(\)phpShell.$phpFile, \(status); \)processes[$i] = $status;

echo $i."

";

}

//exit('这里是子进程');

}

process.php 代码:

file_put_contents('/tmp/process.log', "start

\r\n", FILE_APPEND);

PHP异步实例代码:

//判断OS

\(isWin = false; if(strpos(strtoupper(PHP_OS), 'WIN') !== false) { \)isWin = true;

}

//进程数量控制

if(\(isWin) { \)command = 'tasklist | find "php.exe" /c';

} else {

\(command = "ps -ef | grep 'bin/php -f' | wc -l"; } \)count = 200;

\(limit = 20; \)flag = true;

while(\(flag) { if(\)count <= 0) {

break;

}

\(handler = popen(\)command, 'r');

\(number = fread(\)handler, 512);

echo \(number."\r\n<br/>"; pclose(\)handler);

if($number > $limit) {

//sleep(1);

continue;

}

for($i = 0; $i < 20; \(i++) { \)command = "/usr/local/php5.3/bin/php -f process.php >> /tmp/process.log &";

\(handler = popen(\)command, 'r');

if(!\(handler) { echo "命令执行失败\r\n"; //exit('命令执行失败'); } pclose(\)handler);

}

$count = $count - $limit;

}

exit;