关于PHP实现异步操作的研究


Posted in PHP onFebruary 03, 2013

1.为啥PHP需要异步操作?

一般来说PHP适用的场合是web页面展示等耗时比较短的任务,如果对于比较花时间的操作如resize图片、大数据导入、批量发送EDM、SMS等,就很容易出现操作超时情况。你可以说我可以设置无限超时时间,等等你也要知道PHP有一个工作模式是fastcgi,PHP无限不超时,不代表fastcgi相应不超时……如果你还想说要fastcgi相应永不超时,我建议你应该跟你们的运维人员讨论去……

这个时候异步的操作就发挥他的作用了,由于是非阻塞操作,操作会即时返回,然后在后台再慢慢干活。管你超时不超时的,我就没有在当前的进程/线程下干活。看吧是不是很美好,不过其实这也是个坑……

2.PHP可以实现异步操作吗?

答案是肯定的,不过网上各种的纯PHP实现得就有点别扭了。socket模式、挂起进程模式、有的还直接fork进程。很好,各路神仙各显神通。如果运维人员看到的话,一定会×××××你们的,不把web server跑死才怪……

那还有其他更好的方法去实现这个异步操作的可能么?有,现在我们只有想怎么开外挂了。查一下PECL主流的外挂方案有一堆的××MQ(消息队列),其中有个用于任务分配的外挂进入了我们的视线Gearman(其实这家伙才是角,我就不详细介绍了,点连接看介绍)。

3.为啥选择Gearman?

别的不说,就说他的client多,支持很多语言的client,你可以使用大部分你喜欢的语言去写worker。我个人是很烦语言之争,你喜欢用神码语言写worker都随你喜欢。有数据持久化支持(就是把队列保存到数据库介质中,那故障恢复也好做),有群集支持(其实很多××MQ都有这些功能)。PECL上有扩展,也有纯PHP实现扩展。反正这个Gearman也活了很久了,杂七杂八的问题都基本上解决了。

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的部分先上测试代码:

<?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一样会超时……),这个请留意后续。  

为防止上面的代码无法下载,三水点靠木特打包下载

原文链接:http://my.oschina.net/wakanoc/blog/101789

PHP 相关文章推荐
PHP strncasecmp字符串比较的小技巧
Jan 04 PHP
DEDE采集大师官方留后门的删除办法
Jan 08 PHP
php whois查询API制作方法
Jun 23 PHP
PHP+Mysql+jQuery实现动态展示信息
Oct 08 PHP
PHP文件去掉PHP注释空格的函数分析(PHP代码压缩)
Jul 02 PHP
php截取字符串函数substr,iconv_substr,mb_substr示例以及优劣分析
Jun 10 PHP
PHP获取二维数组中某一列的值集合
Dec 25 PHP
thinkPHP模板中for循环与switch语句用法示例
Nov 30 PHP
php获取今日开始时间和结束时间的方法
Feb 27 PHP
thinkphp 抓取网站的内容并且保存到本地的实例详解
Aug 25 PHP
PHP简单实现防止SQL注入的方法
Mar 13 PHP
Memcached介绍及php-memcache扩展安装
Apr 01 PHP
PHP数组循环操作详细介绍 附实例代码
Feb 03 #PHP
php中将字符串转为HTML的实体引用的一个类
Feb 03 #PHP
php处理文件的小例子(解压缩,删除目录)
Feb 03 #PHP
php函数array_merge用法一例(合并同类数组)
Feb 03 #PHP
php存储过程调用实例代码
Feb 03 #PHP
php中导出数据到excel时数字变为科学计数的解决方法
Feb 03 #PHP
php中删除字符串中最先出现某个字符的实现代码
Feb 03 #PHP
You might like
php 启动时报错的简单解决方法
2014/01/27 PHP
支持生僻字且自动识别utf-8编码的php汉字转拼音类
2014/06/27 PHP
php 中self,this的区别和操作方法实例分析
2019/11/04 PHP
PHP如何通过带尾指针的链表实现'队列'
2020/10/22 PHP
类之Prototype.js学习
2007/06/13 Javascript
javascript 多种搜索引擎集成的页面实现代码
2010/01/02 Javascript
JavaScript中的连字符详解
2013/11/28 Javascript
jquery鼠标放上去显示悬浮层即弹出定位的div层
2014/04/25 Javascript
使用JavaScript实现网页版Pongo设计思路及源代码分享
2014/06/16 Javascript
js查找节点的方法小结
2015/01/13 Javascript
JS实现IE状态栏文字缩放效果代码
2015/10/24 Javascript
Js调用Java方法并互相传参的简单实例
2016/08/11 Javascript
简洁实用的BootStrap jQuery手风琴插件
2016/08/31 Javascript
jquery日历插件e-calendar升级版
2016/11/10 Javascript
使用Ajax生成的Excel文件并下载的实例
2016/11/21 Javascript
JS数组操作中的经典算法实例讲解
2017/07/26 Javascript
vue解决使用webpack打包后keep-alive不生效的方法
2018/09/01 Javascript
详解JS实现系统登录页的登录和验证
2019/04/29 Javascript
jQuery实现二级导航菜单的示例
2020/09/30 jQuery
[54:43]DOTA2-DPC中国联赛 正赛 CDEC vs Dynasty BO3 第一场 2月22日
2021/03/11 DOTA
pip 错误unused-command-line-argument-hard-error-in-future解决办法
2014/06/01 Python
举例讲解Python面向对象编程中类的继承
2016/06/17 Python
利用python实现数据分析
2017/01/11 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
2020/01/10 Python
python 批量下载bilibili视频的gui程序
2020/11/20 Python
Python 求向量的余弦值操作
2021/03/04 Python
HTML5之HTML元素扩展(上)—新增加的元素及使用概述
2013/01/31 HTML / CSS
YSL圣罗兰美妆英国官网:Yves Saint Laurent Beauty UK
2019/08/03 全球购物
慕尼黑山地运动、户外服装和体育用品专家:Sporthaus Schuster
2019/08/27 全球购物
本科生的职业生涯规划范文
2014/01/09 职场文书
校园餐饮创业计划书
2014/01/10 职场文书
优秀教师申报材料
2014/12/16 职场文书
合作合同协议书范本
2015/01/27 职场文书
教师节座谈会主持词
2015/07/03 职场文书
SpringBoot集成Redis的思路详解
2021/10/16 Redis
InterProcessMutex实现zookeeper分布式锁原理
2022/03/21 Java/Android