function a()
{
for ($i = 0; $i < 999999; $i++) {
}
echo 'test';
return true;
}
function b()
{
echo '2';
return true;
}
function cutsBody()
{
$this->a(); //这里不等待a函数返回 直接执行b函数
$this->b();
return true;
}
cutsBody();
执行b函数时不用等待a函数是否返回就执行b函数 知道AJAX可以异步来实现 但我这里用AJAX不方便 有没有其他方法实现?
{
for ($i = 0; $i < 999999; $i++) {
}
echo 'test';
return true;
}
function b()
{
echo '2';
return true;
}
function cutsBody()
{
$this->a(); //这里不等待a函数返回 直接执行b函数
$this->b();
return true;
}
cutsBody();
执行b函数时不用等待a函数是否返回就执行b函数 知道AJAX可以异步来实现 但我这里用AJAX不方便 有没有其他方法实现?
function cutsBody()
{
a(); //这里不等待a函数返回 直接执行b函数
b();
return true;
}
不会function a 没执行完就去执行function b 。
这里的话可以采用任务队列来实现。function a() 往数据库添加一个任务,然后服务器端定时跑一个执行任务的脚本。
a.php文件放function a()和function cutsBody()
b.php文件放function b(),并且直接调用b();将a.php文件中function cutsBody()函数里$this->a();改成用curl请求b.php,这样就是异步的了程序的执行并不会等待curl请求的返回。这相当于开了两个进程。
哇,我对3楼很无语~
直接include不好吗?
下面再来看一个方法,我没搞清楚是为什么,希望大家一起讨论。test.php
<?php
echo 123,'<br/>';
exec("curl 'http://localhost/test2.php' &");
echo 789;test2.php
<?php
sleep(5);
echo 456,'<br/>';
在命令行中使用效果。sh-3.2# curl 'http://www.cutefrog.com/test2.php' &
[1] 3169 //输入上面命令后立刻返回了任务id
sh-3.2# 456<br/> //5秒钟后返回了任务的执行结果。
在shell命令行中,执行的效果与我想象的一样,于是我本以为,也可以拿到php中利用。但实验了一下,却不是我想的那样。sh-3.2# /usr/local/php/bin/php /Users/cutefrog/Sites/test.php
123<br/> % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 8 0 8 0 0 1 0 --:--:-- 0:00:05 --:--:-- 1
789sh-3.2# /usr/local/php/bin/php /Users/cutefrog/Sites/test.php
123<br/> % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 8 0 8 0 0 1 0 --:--:-- 0:00:05 --:--:-- 1
执行到exec("curl 'http://localhost/test2.php' &");这里时,还是需要等待任务执行结果的返回,而不是拿到建立在后台任务后立刻继续。这点我不太理解。
再加个JAVA 计算完成输出
这里有个前提问题,你的计算量是否有大到要开多线程的必要,
test.php
<?php
$ch1 = curl_init();
$ch2 = curl_init();curl_setopt($ch1, CURLOPT_URL, "http://www.cutefrog.com/test2.php");
curl_setopt($ch1, CURLOPT_TIMEOUT, 28);
curl_setopt($ch2, CURLOPT_URL, "http://www.cutefrog.com/test3.php");
curl_setopt($ch2, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_TIMEOUT, 28);$mh = curl_multi_init();curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);echo 'done!';test2.php
<?php
sleep(1);
echo 456,'<br/>';test3.php
<?php
sleep(5);
echo 123;test.php相当于一个线程池,由它去发送对test2.php和test3.php的两个请求,test2.php和test3.php这两个请求之间是异步的,并不会相互等待。但他们对于test.php来说是同步的,test.php必须等待所有线程都回收后才会继续执行。
不过使用这个方法也算是变相模拟了多线程。
搜索到了这么个贴子:http://topic.csdn.net/t/20050228/10/3811220.html,
手册里有一句:
Note:If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.不知道会不会跟这个有关
<?php
$ch1 = curl_init();
$ch2 = curl_init();curl_setopt($ch1, CURLOPT_URL, "http://www.cutefrog.com/test2.php");
curl_setopt($ch1, CURLOPT_TIMEOUT, 28);
curl_setopt($ch2, CURLOPT_URL, "http://www.cutefrog.com/test3.php");
curl_setopt($ch2, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_TIMEOUT, 28);$mh = curl_multi_init();curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);echo 'done!';test2.php
<?php
sleep(5);
echo 123,'<br/>';test3.php
<?php
sleep(1);
echo 456,'<br/>';请看这个例子:
用test.php先请求test2.php后请求test3.php。
如果它们是同步执行的话,无论怎么sleep,都应该是先请求test2.php,后请求test3.php,那么最后的结果就应该为:
123
456
done!没错把?
可是这个例子的最后结果是
456
123
done!我虽然是先调用的test2.php,但由于他sleep了5秒,而test3.php只sleep了1秒。所以test3.php比test2.php先执行完毕。这就证明了,他们之间是异步的,这两个请求是同时发出去的,但不是同时收回的。
2:通过fork子进程
手册说了,要异步用passthru不过,一般还是想先知道楼主的原始需求,很多时候是有其它办法的...
第一部分 模拟POST头
/**
+----------------------------------------------------------
* 函数 sendHeader
* 发送模拟头信息
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param Array $params 数据数组
* @param String $sessid 模拟session
+----------------------------------------------------------
* @return resource
+----------------------------------------------------------
*/
public function sendHeader($params = array(), $sessid = '')
{
$header = null;
$body = null;
$query_str = null;
if (function_exists('fsockopen')) {
$fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if (! $fp) {
return false;
}
$send_str = "{$this->method} {$this->path}{$this->query} HTTP/1.0\r\n";
$send_str .= "Host:{$this->host}:{$this->port}\r\n";
$send_str .= "Accept: */*\r\n";
$send_str .= "Referer:{$this->referer}\r\n";
$send_str .= "User-Agent: " . self::SEND_USER_AGENT . "\r\n";
$send_str .= "Pragma: no-cache\r\n";
$send_str .= "Cache-Control: no-cache\r\n";
//如果是POST方法,分析参数
if ($this->method == 'POST') {
//判断参数是否是数组,循环出查询字符串
if (is_array($params)) {
if (! isset($params[1])) //允许附带POST数据 支持同名
$query_str = http_build_query($params);
if (isset($params[1]))
$query_str = http_build_query($params[0]) . $params[1];
} else {
$query_str = $params;
}
$length = strlen($query_str);
$send_str .= "Content-Type: application/x-www-form-urlencoded\r\n";
$send_str .= "Content-Length: {$length}\r\n";
}
//新增伪造session 2011/08/26
if (! empty($sessid)) {
$send_str .= "Cookie: $sessid" . "\n";
}
$send_str .= "Connection: Close\r\n\r\n";
if (strlen($query_str) > 0) {
$send_str .= $query_str . "\r\n";
}
fputs($fp, $send_str);
return $fp;
} else {
//创建一个用于存放cookie信息的临时文件
$ch = curl_init($this->url);
curl_setopt_array($ch, array(
CURLOPT_TIMEOUT => $this->timeout, CURLOPT_HEADER => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => self::SEND_USER_AGENT, CURLOPT_REFERER => $this->referer, CURLOPT_COOKIESESSION => true, CURLOPT_COOKIEFILE => $sessid //把之前保存的cookie发送到服务器
));
if ($this->method == 'GET') {
curl_setopt($ch, CURLOPT_HTTPGET, true);
} else {
if (is_array($params)) {
if (! isset($params[1]))
$query_str = http_build_query($params);
if (isset($params[1]))
$query_str = http_build_query($params[0]) . $params[1];
} else {
$query_str = $params;
}
if ($this->method == 'POST')
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $query_str);
}
$fp = curl_exec($ch);
curl_close($ch);
if (! $fp) {
return false;
}
return $fp;
}
}
第二部分 取返回header头
/**
* rtnHeader
* 返回服务器信息
* @param unknown_type $fp
*/
public function cutsHeader($fp)
{
$header = '';
do {
$header .= fread($fp, 1);
} while (! preg_match("/\r\n\r\n$/", $header));
$this->header = $header;
return $header;
}
第三部分 就是最重要的 读取文件数据了
/**
* rtnHeader
* 返回服务器信息
* @param unknown_type $fp
*/
public function cutsBody($fp)
{
$body = '';
//判断获取类型支持多线程分块读取
/* if (str_exists($this->header, 'application/x-zip-compressed')){
$dfp = fopen('demo.txt', 'a+');
while (! feof($fp)) {
$body = fgets($fp, 1024);
fwrite($dfp, $body);
}
fclose($dfp);
}else{*/
while (! feof($fp)) {
$body .= fgets($fp, 1024);
}
// }
return $body;
}
就是这里 看有没有其他方法不顺序读取$fp资源 能够分段读取 最后在组合文件!这是我最初的想法~
http://ca2.php.net/manual/en/function.ftp-nb-fget.php如果是http下载,curl或socket续传的方法可以参考这里:
http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/
至于non-blocking,这个php函数可以用于socket,
http://ca2.php.net/manual/en/function.stream-set-blocking.php
curl应该也可以non-block,但一时没找到合适的资料,你有兴趣可以找找.