python - Python 子流程模块:如何重新打开 PIPE?
问题描述
我有一段代码需要运行 node js。为了写入文件以供节点 js 接收命令,我使用以下代码:
def execute(comm):
file_number = proc.stdin.fileno()
file = open(file_number, "w+")
file.write(comm)
file.close()
execute("""console.log("hi");""")
execute("""console.log("bye");""")
但是,当我第二次运行执行时,出现以下错误:
OSError: [WinError 6] The handle is invalid
这个错误是什么意思,我该如何解决?这是完整的代码:
import subprocess
import threading
import time
class nodePrompt:
def __init__(self):
self.proc = subprocess.Popen("node", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
self.on_out_func = print
self.on_out_args=[]
self.on_out_kwargs={}
self.on_err_func = print
self.on_err_args=[]
self.on_err_kwargs={}
self.on_out_thread=None
self.on_err_thread=None
def execute(self, comm):
file_number = self.proc.stdin.fileno()
file = open(file_number, "w+")
file.write(comm)
file.close()
def on_out(function, *args, **kwargs):
self.on_out_func=function
self.on_out_args=args
self.on_out_kwargs=kwargs
def on_err(function, *args, **kwargs):
self.on_err_func=function
self.on_err_args=args
self.on_err_kwargs=kwargs
def on_out_handle(self):
for i in iter(self.proc.stdout.readline, ""):
self.on_out_func(i, *self.on_out_args, **self.on_out_kwargs)
def start_on_out(self, daemon=False):
self.on_out_thread=threading.Thread(target=self.on_out_handle)
self.on_out_thread.setDaemon(daemon)
self.on_out_thread.start()
def on_err_handle(self):
for i in iter(self.proc.stderr.readline, ""):
self.on_err_func(i, *self.on_err_args, **self.on_err_kwargs)
def start_on_err(self, daemon=False):
self.on_err_thread=threading.Thread(target=self.on_err_handle)
self.on_err_thread.setDaemon(daemon)
self.on_err_thread.start()
prompt = nodePrompt()
prompt.start_on_out()
prompt.start_on_err()
prompt.execute("console.log(\"HI\");")
time.sleep(1)
prompt.execute("console.log(\"HI\");")
解决方案
关闭的 FIFO 无法重新打开。你所能做的就是在你真正完成之前不要关闭它。改为使用flush()
以确保立即发生写入。
这是 node.js 在其输入和输出进入管道时没有增量运行代码(或不刷新其输出)的问题。在修复您的代码以self.proc.stdin
直接使用之后,Python 可以证明是正确的。
即修改后execute
定义为:
def execute(self, comm):
self.proc.stdin.write(comm)
self.proc.stdin.flush()
...我们可以监控 Python 解释器和它启动的 node.js 副本的活动。
不幸的是,node
它的行为不像你想要的那样。
请注意以下跟踪的时间戳,它用于sysdig
跟踪程序执行期间的操作:
5178 18:55:37.047606506 4 python (18260) < write res=19 data=console.log("HI");.
8239 18:55:37.095849210 1 node (18261) < read res=19 data=console.log("HI");.
8590 18:55:38.048679102 4 python (18260) < write res=19 data=console.log("HI");.
8595 18:55:38.048710436 4 python (18260) < close res=0
8597 18:55:38.048742124 1 node (18261) < read res=19 data=console.log("HI");.
8603 18:55:38.048911687 1 node (18261) < read res=0 data=
8633 18:55:38.051116830 1 node (18261) < write res=3 data=HI.
8634 18:55:38.051158022 6 python (18262) < read res=3 data=HI.
8636 18:55:38.051199286 6 python (18262) < write res=3 data=HI.
8642 18:55:38.051400907 1 node (18261) < write res=3 data=HI.
8643 18:55:38.051441455 6 python (18262) < read res=3 data=HI.
8645 18:55:38.051459654 6 python (18262) < write res=3 data=HI.
Python 编写第一个console.log("HI")
,Node 读取它,早在 Node 写入任何输出之前。
我建议查看 Node 是否运行来自非 TTY 源的代码,或者它是否尝试将整个流读取到末尾并在运行任何内容之前对其进行解析。
推荐的复制器
如果您要向节点受众提出这个问题,请考虑为他们提供以下 bash 脚本:
{
echo 'console.log("HI");'
sleep 1
echo 'console.log("HI");'
sleep 1
echo "Already sent both commands to node" >&2
} | node
它的输出是:
Already sent both commands to node
HI
HI
...而人们可能希望早点打印至少一个 HI,因为在发送第一个命令后有整整两秒的延迟。
推荐阅读
- python - 只有当一个函数被调用时,你如何继续一个while循环?
- javascript - 如何更改悬停项目的颜色?
- javascript - 将 JavaScript 对象转换为类似项目
- azure - 在 Azure 中禁用更改跟踪
- python - 如何让 .__repr__() 正常工作?
- javascript - Javascript 在继续尝试回调和承诺之前不等待处理
- python - ORA-01036: 非法变量名称/编号 (cx_Oracle)
- google-cloud-platform - 尝试拉取大于 50KB 的消息时,PubSubPullSensor 失败
- python - 如何将凌乱的 html 表转换为 pandas 数据框
- python - 加载 CrossValidator 对象 Pyspark