Rumah > pembangunan bahagian belakang > tutorial php > 关于PHP实现异步操作的研究_PHP

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

WBOY
Lepaskan: 2016-06-01 12:06:55
asal
832 orang telah melayarinya

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

<ol class="dp-c">
<li class="alt"><span><span><?php </span></span></span></li>
<li>
<span class="keyword">require_once</span><span> </span><span class="string">'PHPAsyncClient.php'</span><span>;  </span>
</li>
<li class="alt">
<span>date_default_timezone_set(</span><span class="string">'Asia/Shanghai'</span><span>);  </span>
</li>
<li><span> </span></li>
<li class="alt">
<span class="keyword">class</span><span> AsyncTest {  </span>
</li>
<li><span> </span></li>
<li class="alt">
<span>    </span><span class="keyword">const</span><span> </span>
</li>
<li>
<span>        LOG_FILE = </span><span class="string">'/debug.log'</span><span>;  </span>
</li>
<li class="alt"><span> </span></li>
<li>
<span>    </span><span class="keyword">static</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> run() {  </span>
</li>
<li class="alt">
<span>        </span><span class="keyword">if</span><span> (PHPAsyncClient::in_callback(</span><span class="keyword">__FILE__</span><span>)) {  </span>
</li>
<li>
<span>            self::log(</span><span class="string">'php Async callback'</span><span>);  </span>
</li>
<li class="alt"><span>            PHPAsyncClient::parse();  </span></li>
<li>
<span>            </span><span class="keyword">return</span><span>;  </span>
</li>
<li class="alt"><span>        }  </span></li>
<li>
<span>        </span><span class="keyword">if</span><span> (PHPAsyncClient::is_main(</span><span class="keyword">__FILE__</span><span>)) {  </span>
</li>
<li class="alt">
<span>            self::log(</span><span class="string">'main run'</span><span>);  </span>
</li>
<li>
<span>            </span><span class="vars">$async_call</span><span> = PHPAsyncClient::getInstance();  </span>
</li>
<li class="alt">
<span>            </span><span class="vars">$async_call</span><span>->AsyncCall(</span><span class="string">'AsyncTest'</span><span>, </span><span class="string">'callback'</span><span>, </span><span class="keyword">array</span><span>(  </span>
</li>
<li>
<span>                </span><span class="string">'content'</span><span> => </span><span class="string">'Hello World!!!'</span><span>,  </span>
</li>
<li class="alt">
<span>            ), </span><span class="keyword">array</span><span>(  </span>
</li>
<li>
<span>                </span><span class="string">'class'</span><span> => </span><span class="string">'AsyncTest'</span><span>,  </span>
</li>
<li class="alt">
<span>                </span><span class="string">'method'</span><span> => </span><span class="string">'callback'</span><span>,  </span>
</li>
<li>
<span>                </span><span class="string">'params'</span><span> => </span><span class="keyword">array</span><span>(  </span>
</li>
<li class="alt">
<span>                    </span><span class="string">'content'</span><span> => </span><span class="string">'Hello Callback!'</span><span>,  </span>
</li>
<li><span>                ),  </span></li>
<li class="alt">
<span>            ), </span><span class="keyword">__FILE__</span><span>);  </span>
</li>
<li>
<span>            </span><span class="keyword">return</span><span>;  </span>
</li>
<li class="alt"><span>        }  </span></li>
<li><span>    }  </span></li>
<li class="alt"><span> </span></li>
<li>
<span>    </span><span class="keyword">static</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> callback(</span><span class="vars">$args</span><span>) {  </span>
</li>
<li class="alt">
<span>        self::log(</span><span class="string">'AsyncTest callback run'</span><span>);  </span>
</li>
<li>
<span>        self::log(</span><span class="string">'AsyncTest callback args:'</span><span>.print_r(</span><span class="vars">$args</span><span>, true));  </span>
</li>
<li class="alt"><span>    }  </span></li>
<li><span> </span></li>
<li class="alt">
<span>    </span><span class="keyword">static</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> log(</span><span class="vars">$content</span><span>) {  </span>
</li>
<li>
<span>        </span><span class="vars">$fullname</span><span> = dirname(</span><span class="keyword">__FILE__</span><span>).self::LOG_FILE;  </span>
</li>
<li class="alt">
<span>        </span><span class="vars">$content</span><span> = </span><span class="func">date</span><span>(</span><span class="string">'[Y-m-d H:i:s]'</span><span>).</span><span class="vars">$content</span><span>.</span><span class="string">"\n"</span><span>;  </span>
</li>
<li>
<span>        </span><span class="func">file_put_contents</span><span>(</span><span class="vars">$fullname</span><span>, </span><span class="vars">$content</span><span>, FILE_APPEND);  </span>
</li>
<li class="alt"><span>    }  </span></li>
<li><span>}  </span></li>
<li class="alt"><span> </span></li>
<li><span>AsyncTest::run(); </span></li>
</ol>
Salin selepas log masuk

就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

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan