1.为啥PHP须要异步操做?javascript
通常来讲PHP适用的场合是web页面展现等耗时比较短的任务,若是对于比较花时间的操做如resize图片、大数据导入、批量发送EDM、SMS等,就很容易出现操做超时状况。你能够说我能够设置无限超时时间,等等你也要知道PHP有一个工做模式是fastcgi,PHP无限不超时,不表明fastcgi相应不超时……若是你还想说要fastcgi相应永不超时,我建议你应该跟大家的运维人员讨论去……php
这个时候异步的操做就发挥他的做用了,因为是非阻塞操做,操做会即时返回,而后在后台再慢慢干活。管你超时不超时的,我就没有在当前的进程/线程下干活。看吧是否是很美好,不过其实这也是个坑……html
2.PHP能够实现异步操做吗?java
答案是确定的,不过网上各类的纯PHP实现得就有点别扭了。socket模式、挂起进程模式、有的还直接fork进程。很好,各路神仙各显神通。若是运维人员看到的话,必定会×××××大家的,不把web server跑死才怪……node
那还有其余更好的方法去实现这个异步操做的可能么?有,如今咱们只有想怎么开外挂了。查一下PECL主流的外挂方案有一堆的××MQ(消息队列),其中有个用于任务分配的外挂进入了咱们的视线Gearman(其实这家伙才是角,我就不详细介绍了,点链接看介绍)。python
3.为啥选择Gearman?linux
别的不说,就说他的client多,支持不少语言的client,你可使用大部分你喜欢的语言去写worker。我我的是很烦语言之争,你喜欢用神码语言写worker都随你喜欢。有数据持久化支持(就是把队列保存到数据库介质中,那故障恢复也好作),有群集支持(其实不少××MQ都有这些功能)。PECL上有扩展,也有纯PHP实现扩展。反正这个Gearman也活了好久了,杂七杂八的问题都基本上解决了。web
4.基本思路数据库
有了Gearman这外挂就简单多了。就是向gearman发送一个任务,把执行的任务发出去,而后等待worker去调用PHP cli去运行咱们的php代码。编程
我就写了一下一个python的worker(别问我为啥用python,1.我会python,2.linux下不用装runtime),你能够本身根据思路写一个PHP的worker,不过嘛,本人是不太信得过PHP跑的worker。其余语言饭能够用java、node.js 或者其余语言实现一个worker试试。对用Golang写worker有兴趣的朋友能够找我。
phpasync_worker_py
很差意思,里面是没有注释的。一个配置文件,一个py脚本。基本的功能也就是分析一下调用的参数,而后调用PHP Cli,就是那样子而已。要让py脚本跑起来请自行安装python的gearman模块。
而后到PHP的部分先上测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<?php
require_once
'PHPAsyncClient.php'
;
date_default_timezone_set(
'Asia/Shanghai'
);
class
AsyncTest {
const
LOG_FILE =
'/debug.log'
;
static
public
function
run() {
if
(PHPAsyncClient::in_callback(
__FILE__
)) {
self::log(
'php Async callback'
);
PHPAsyncClient::parse();
return
;
}
if
(PHPAsyncClient::is_main(
__FILE__
)) {
self::log(
'main run'
);
$async_call
= PHPAsyncClient::getInstance();
$async_call
->AsyncCall(
'AsyncTest'
,
'callback'
,
array
(
'content'
=>
'Hello World!!!'
,
),
array
(
'class'
=>
'AsyncTest'
,
'method'
=>
'callback'
,
'params'
=>
array
(
'content'
=>
'Hello Callback!'
,
),
),
__FILE__
);
return
;
}
}
static
public
function
callback(
$args
) {
self::log(
'AsyncTest callback run'
);
self::log(
'AsyncTest callback args:'
.print_r(
$args
, true));
}
static
public
function
log(
$content
) {
$fullname
= dirname(
__FILE__
).self::LOG_FILE;
$content
=
date
(
'[Y-m-d H:i:s]'
).
$content
.
"\n"
;
file_put_contents
(
$fullname
,
$content
, FILE_APPEND);
}
}
AsyncTest::run();
|
就3个静态方法,一个是用于调试的log方法,其余都是字面意思。这个例子是对这种调用方式有个初步印象。而后直接上PHP的全部源码:
php_async.zip
而后应该会有不少人会说,win下安装不了gearman……因此我把java版的gearman server也放上去吧。
java-gearman-service-0.6.6.zip
5.结论
通过以上配置犀牛同样大的家伙后(要装一个Gearman,还要跑个Py脚本),咱们基本上就使PHP拥有了异步调用功能,固然其中还有一个状态维护神马的要本身去实现。因此发现,其实这个方案不咋样,太复杂了。仍是使用一些web service的方式去作web callback会好点(问题是web callback同样会超时……),这个请留意后续。
*******************************************
php 异步调用方法
客户端与服务器端是经过HTTP协议进行链接通信,客户端发起请求,服务器端接收到请求后执行处理,并返回处理结果。
有时服务器须要执行很耗时的操做,这个操做的结果并不须要返回给客户端。但由于php是同步执行的,因此客户端须要等待服务处理完才能够进行下一步。
所以对于耗时的操做适合异步执行,服务器接收到请求后,处理完客户端须要的数据就返回,再异步在服务器执行耗时的操做。
原理,服务器返回的html中插入Ajax 代码或 img 标记,img的src为须要执行的程序。
优势:实现简单,服务端无需执行任何调用
缺点:在执行期间,浏览器会一直处于loading状态,所以这种方法并不算真正的异步调用。
使用popen执行命令,语法:
缺点:1.只能在本机执行
2.不能传递大量参数
3.访问量高时会建立不少进程。
设置curl的超时时间 CURLOPT_TIMEOUT 为1 (最小为1),所以客户端须要等待1秒
fsockopen是最好的,缺点是须要本身拼接header部分。
Tips:关于fsockopen的介绍与用法能够参考我以前写的《php 利用fsockopen GET/POST 提交表单及上传文件》与《PHP HTTP请求类,支持GET,POST,Multipart/form-data》
**************************************