如何正确处理生成的 child_process 的 stdio?
Posted
技术标签:
【中文标题】如何正确处理生成的 child_process 的 stdio?【英文标题】:How to properly handle the stdio of a spawned child_process? 【发布时间】:2021-12-31 10:12:15 【问题描述】:我正在处理子进程。我正在制作一款游戏(几乎处于完成的最后阶段),现在我发现了一个严重的问题。
基本上,在游戏中,我有一个基于 javascript 的服务器,它使用 child_process 来spawn
一个运行 python 脚本的子进程。 python 脚本处理游戏机制,js 代码处理服务器-客户端系统。我需要一个 js 和我的 python 代码之间的通信系统。使用文档和其他资源,我已经成功设置了这样一个系统,但一段时间后,它停止工作。
这里是复制问题的代码:-
Javascript (temp.js):
"use strict";
const childProcess = require('child_process');
let pythonProcess = childProcess.spawn("python", ["temp2.py"], cwd: "./private/PythonScripts/Temp/");
pythonProcess.stdin.setDefaultEncoding("utf-8");
pythonProcess.stdout.setEncoding("utf-8");
const writeString = "" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"; // 8x 128 Zeros
pythonProcess.stdout.on("error", (err) =>
console.log("Stdout Error");
if (err)
console.log(err);
);
let count = 0;
setInterval(() =>
count++;
console.log(count);
pythonProcess.stdin.write(writeString, (err) =>
if (err)
console.log("Error during writing");
console.log(err);
);
, 100);
Python (3.10.x) (temp2.py):
import logging
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[logging.FileHandler('temp.log', 'w+', 'utf-8'), logging.StreamHandler()],
level=logging.INFO)
tempLogger = logging.getLogger(__name__)
if __name__ == '__main__':
tempLogger.info("Started")
while True:
inp = input()
tempLogger.info(inp)
目录结构:
temp.js
private
|
|-> PythonScripts
|
|-> Temp
|
|-> temp2.py
|-> temp.log
当我们运行这段代码时,我们会看到 js 成功地继续写入(我假设是因为err
总是undefined
),但是 python 只会记录输入只有 79 次。
我的预感是这个问题与缓冲区/管道溢出有关,并且它们没有被耗尽,但是在搜索所有文档以查找 child_process 并为 python 记录/输入之后,我无法弄清楚问题出在哪里,即正在阻止脚本之间的通信。
我该怎么做才能使数据流不会像现在一样卡住。
【问题讨论】:
【参考方案1】:所以,我终于想通了。
问题是,我设置记录器的方式,记录器将写入日志文件以及控制台。
但由于进程是使用 child_process 创建的,我们无法看到。在我的主代码中,我为pythonProcess.stdout.on("data", (data) => ...);
设置了回调,但我们仍然看不到这些日志。当我独立运行脚本时,我注意到控制台的额外打印。最后,我可以通过为pythonProcess.stderr.on("data", (data) => ...);
设置处理程序来查看日志。
有两个修复:-
只需停止记录器登录控制台即可。 Python 代码将是: -
(不要使用basicConfig()
)
import logging.handlers
tempLogger = logging.getLogger(__name__)
tempLogger.setLevel(logging.DEBUG)
handler = logging.handlers.WatchedFileHandler('temp.log', 'w+', 'utf-8')
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S'))
tempLogger.addHandler(handler)
if __name__ == '__main__':
tempLogger.info("Started")
with open("temp.txt", "r") as in_file:
while True:
for line in in_file.readlines():
if line != "":
line = line.rstrip("\r\n")
tempLogger.debug(line)
像我上面提到的pythonProcess.stderr.on("data", (data) => ...);
那样为子进程的stderr 设置一个处理程序。这将清除 stderr 缓冲区,并且日志记录现在会卡住。
【讨论】:
以上是关于如何正确处理生成的 child_process 的 stdio?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Node.JS 中获取生成的 child_process 的输出?
nodejs child_process.spawnSync 或 child_process.spawn 包裹在 yieldable 生成器中,它返回输出
node.js 安全/转义中的 child_process 生成
使用命名管道作为标准输入生成节点 child_process
如何使用 Bluebird 承诺 Node 的 child_process.exec 和 child_process.execFile 函数?