在Python线程内运行子进程,实时读取输出

问题描述 投票:0回答:1

考虑以下 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 命令的输出)

我的问题是:

  • 我该如何解释这种行为?

  • 在单独的线程中运行进程是个好主意还是我应该使用不同的方法? 这篇文章表明它不是...

  • 如何修复代码?

谢谢!

multithreading process python-2.x
1个回答
0
投票

启动线程后永远不应该分叉。 您可以在启动 fork 后使用线程,这样您就可以让线程处理 I/O 管道,但是...

让我重复一遍:启动线程后永远不应该分叉

那篇文章解释得很好。 一旦启动线程,您就无法控制程序的状态。 尤其是在 Python 中,事情在后台发生。

要修复代码,只需从主线程启动子进程,然后启动线程即可。 在线程中处理来自管道的 I/O 是完全可以的。

© www.soinside.com 2019 - 2024. All rights reserved.