PHP如何分时段向Python脚本发送非定时触发的输入参数
实现方案
这个需求完全可以实现,核心要解决的问题是:常规PHP进程调用方式(system/exec/proc_open)启动的Python进程会和PHP进程生命周期绑定,PHP退出时Python进程会被系统回收,没法做到跨请求等待第二个输入。用命名管道(FIFO)做持久化进程间通信即可满足所有要求,不需要定时等待,也不需要一次性传完所有参数。
实现原理
通过Linux命名管道做中转,把Python进程的标准输入、输出重定向到两个持久化的管道文件,让Python以常驻后台的方式脱离PHP请求生命周期运行:
- Python输出的输入提示会实时写入输出管道,PHP需要传值时直接读管道即可,读操作天然阻塞,有内容才返回,不需要sleep轮询
- PHP把输入值写入输入管道,Python就会像接收到命令行输入一样继续执行
- 传完第一个值后PHP可以直接退出,Python会持续在后台等待下一个输入,等待时长没有限制
具体实现步骤
1. 提前创建命名管道
在服务器上执行以下命令创建两个管道文件,配置好读写权限:
mkfifo /tmp/python_in.fifo mkfifo /tmp/python_out.fifo chmod 666 /tmp/python_*.fifo
2. 启动常驻Python进程
执行命令启动Python进程,注意必须加-u参数禁用Python输出缓冲,否则提示内容会卡在内存缓冲区不会写入管道:
nohup python3 -u /path/to/your/python_file.py < /tmp/python_in.fifo > /tmp/python_out.fifo 2>&1 &
执行完后Python就会在后台运行,等待第一个输入提示。
3. PHP端交互代码
第一次请求(发送第一个输入值1)
不需要等后续流程,传完值直接退出即可:
<?php // 读取Python输出的第一个提示 $outFp = fopen('/tmp/python_out.fifo', 'r'); $prompt = fread($outFp, 1024); // 阻塞等待,直到读到提示内容,无需sleep if (trim($prompt) === 'First input:') { $inFp = fopen('/tmp/python_in.fifo', 'w'); // 注意必须加换行符,Python的input()函数读到换行才会判定输入结束 fwrite($inFp, "1\n"); fclose($inFp); } fclose($outFp); // 到这里PHP逻辑可以直接结束,Python会在后台继续等待第二个输入
第二次请求(需要发送第二个输入值2时再执行)
什么时候要传第二个值,什么时候跑这段逻辑就行,没有时间限制:
<?php // 读取Python输出的第二个提示 $outFp = fopen('/tmp/python_out.fifo', 'r'); $prompt = fread($outFp, 1024); if (trim($prompt) === 'Second input:') { $inFp = fopen('/tmp/python_in.fifo', 'w'); fwrite($inFp, "2\n"); fclose($inFp); // 如果Python拿到两个输入后有执行结果,继续读管道即可拿到返回内容 // $result = stream_get_contents($outFp); } fclose($outFp);
注意事项
- 必须给Python加
-u参数,否则输出缓冲会导致PHP读不到实时提示,一直卡住。 - 写入输入值时必须在末尾加
\n换行符,否则Python的input()会一直等待输入结束,不会往下执行。 - 要保证PHP运行用户(通常为www-data、nginx)和启动Python进程的用户对两个fifo文件有读写权限,否则会报权限错误。
- 如果有多个并发对接场景,不要共用一套管道,可以每次启动Python进程时生成带唯一标识的管道文件名(比如用请求ID、进程ID做后缀),避免数据串流。
- 如果是Windows环境,没有原生的shell级命名管道支持,可以换成本地TCP socket方案:Python端常驻监听本地端口,PHP需要交互时连接端口读提示、发数据,逻辑和FIFO方案完全一致。
内容的提问来源于stack exchange,提问作者TheFaultInOurStars
相关产品推荐
相关产品推荐

