blog/_posts/2023-03-12-php-async.md

21 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
layout: post
title: PHP异步执行的探索
tags: [PHP, 异步]
---
看来异步总是个难以解决的问题啊……<!--more-->
# 起因
最近我在写一个ThinkPHP框架为基础的代码时遇到了一个问题我希望在执行完一个操作后立马返回数据然后在后台继续运行一个比较耗时的东西。我以前写的一个[图片机器人](/2021/02/23/picbotpro.html)其实也遇到过这种问题为了解决返回很慢的问题我采用了“离弦之箭”——使用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](https://www.php.net/manual/zh/function.fastcgi-finish-request.php)它可以在程序结束前把要输出的东西输出并且结束请求不过使用它以后看文档说明好像说推荐再执行一下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来做异步果然是难事啊不如说大多数程序想要处理好多线程的问题都挺难的吧也许如果项目经常遇到这种问题应该考虑用其他语言来编写了呢。