Mayx的博客

Logo

Mayx's Home Page

View My GitHub Profile

About Me

12 March 2023 - 字数统计:1312 - 阅读大约需要4分钟 - Hits: Loading...

PHP异步执行的探索

by mayx


看来异步总是个难以解决的问题啊……

起因

最近,我在写一个ThinkPHP框架为基础的代码时遇到了一个问题,我希望在执行完一个操作后立马返回数据,然后在后台继续运行一个比较耗时的东西。我以前写的一个图片机器人其实也遇到过这种问题,为了解决返回很慢的问题,我采用了“离弦之箭”——使用file_get_contents函数请求自己,并且使用’timeout’参数来防止页面挂起,另外接收的部分使用ignore_user_abort(true)set_time_limit(0)保证在请求结束时让程序依然继续运行。不过我用的是TP框架啊,不知道用那两个函数会不会出问题,还有这个“timeout”到底填多少比较合适也不确定,所以就想试试别的方法。

探索异步的方法

对于正规的情况来说,直接去网上搜如何让PHP异步执行代码,估计大多会说使用什么消息队列或者用什么Swoole框架吧,或者简单点用popen函数来fork一个进程,或者用什么fsockopen,貌似原理和我用file_get_contents函数差不多?其实吧我觉得从本质来说那个所谓的Swoole框架已经不算PHP的东西了,我觉得它更像是一个能通过http请求的popen函数,通过某种方式也一样是在本地去调用PHP脚本,只是可能用了些什么比如线程啥的特性提高了性能而已。
我看完这些选择之后很不满意,我不希望代码里出现popen这样的函数,说实话这是个危险的函数,绝大多数情况下服务器应该要禁用这种函数的,毕竟如果因为某些原因被人上传了PHP木马,他们可以直接用这个函数去执行命令了。至于什么乱七八糟的异步框架,想不想学是一方面,主要是我的项目还没有达到用这种东西的规模。那难不成我只能继续用之前图片机器人的那个“离弦之箭”的办法了吗?
后来我找到了一个很不错的函数,叫做fastcgi_finish_request,它可以在程序结束前把要输出的东西输出并且结束请求,不过使用它以后看文档说明好像说推荐再执行一下session_write_close函数,不然在这个程序执行完成前session会被锁住,没法操作。
不过这个函数只能在使用PHP-FPM的时候使用,如果是像Apache那样使用模块的方式运行PHP估计就用不了了,当然目前大多数环境应该都用的是Nginx+PHP-FPM吧,我反正是很少见到有人用Apache,虽然听说那样性能似乎会更好?
还有一个问题就是如果这个需要运行的脚本的时间太长了,以至于同时运行这个脚本的进程数量超过了pm.max_children,那么PHP-FPM就不能接受新的请求了,这也是一个缺陷。
另外在这种情况下我使用了TP框架还会遇到一个问题,那就是我不能使用return返回内容了,毕竟return了之后就不能执行其他函数了啊,所以就只能提前用echo之类的东西输出,执行完fastcgi_finish_request和所有需要长时间运行的代码后就只能return空值或者直接exit吧。

感想

看来用PHP来做异步果然是难事啊,不如说大多数程序想要处理好多线程的问题都挺难的吧,也许如果项目经常遇到这种问题,应该考虑用其他语言来编写了呢。

tags: PHP - 异步
召唤伊斯特瓦尔