考虑以下 Python 代码:
import io
import time
import subprocess
import sys
from thread import start_new_thread
def ping_function(ip):
filename = 'file.log'
command = ["ping", ip]
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
process = subprocess.Popen(command, stdout=writer)
while process.poll() is None:
line = reader.read()
# Do something with line
sys.stdout.write(line)
time.sleep(0.5)
# Read the remaining
sys.stdout.write(reader.read())
ping_function("google.com")
目标是运行 shell 命令(在本例中为 ping,但与此处无关)并实时处理输出,该输出也保存在日志文件中。
换句话说,ping在后台运行,每秒都会在终端上产生输出。我的代码将读取此输出(每 0.5 秒),解析它并(几乎)实时采取一些操作。
这里的实时意味着我不想等待进程结束来读取输出。在这种情况下,实际上 ping 永远不会完成,因此像我刚才描述的方法是强制性的。
我已经测试了上面的代码,它实际上工作正常:)
现在我想在一个单独的线程中调整它,所以我用以下内容替换了最后一行:
from thread import start_new_thread
start_new_thread(ping_function, ("google.com", ))
由于某种原因,这不再起作用,并且阅读器总是返回空字符串。 特别是,reader.read()返回的字符串始终为空。
使用队列或其他全局变量不会有帮助,因为我什至在检索数据时都遇到问题(即获取 shell 命令的输出)
我的问题是:
我该如何解释这种行为?
在单独的线程中运行进程是个好主意还是我应该使用不同的方法? 这篇文章表明它不是...
如何修复代码?
谢谢!
启动线程后永远不应该分叉。 您可以在启动 fork 后使用线程,这样您就可以让线程处理 I/O 管道,但是...
让我重复一遍:启动线程后永远不应该分叉
那篇文章解释得很好。 一旦启动线程,您就无法控制程序的状态。 尤其是在 Python 中,事情在后台发生。
要修复代码,只需从主线程启动子进程,然后启动线程即可。 在线程中处理来自管道的 I/O 是完全可以的。