【问题标题】:How to get asynchronous input AND output using subprocess.POPEN如何使用 subprocess.POPEN 获取异步输入和输出
【发布时间】:2016-01-18 20:44:48
【问题描述】:

我已经为此工作了几个小时,但未能提出一个好的解决方案。一点背景知识,我正在运行一个密码破解程序,该程序从命令行关闭源代码,但当我的 gpu 温度太高时必须不断暂停它。

我使用这个程序在 python 中进行其他操作,所以这是我更喜欢的语言。无论如何,密码程序会定期更新它的运行情况、gpu 温度等,并允许我随时暂停它。

我的温度正常,但由于阻塞问题,我猜我无法发送暂停命令。至少它什么也没做。我见过几个线程化输出的例子,但还没有看到使用线程化输入和输出而不会导致任何问题的东西。

我的意思是,据我所知,在当前的 POPEN 限制下这可能是不可能的,但希望有一些方向。

popen = Popen(command, stdout=PIPE, stdin=PIPE, shell=True)
lines_iterator = iter(popen.stdout.readline, b"")
while 1:
    for line in lines_iterator:
        cleanLine = line.replace("\n", "")
        p = re.compile('[0-9][0-9]c Temp')
        m = p.search(cleanLine)
        print cleanLine
        if m:
            temperature = m.group(0)
            if int(temperature[:2]) > 80:
                overheating = True
                print "overheating"
        if overheating:
            if "[s]tatus [p]ause [r]esume [b]ypass [q]uit" in line:

                #It's not doing anything right here, it just continues
                print popen.communicate("p")[0]

这是我的代码的要点。它仍然处于 hacky 阶段,所以我知道它可能没有遵循最佳编码实践。

【问题讨论】:

  • 我们有机会自己尝试 pwdcrack 吗?
  • 这是 OCLhashcat。这是我迄今为止使用过的最好的 gpu 饼干,但我的机器每 15 分钟左右就会超过 80 度,我必须持续监控它,这很痛苦。我只是想自动化更多。

标签: python multithreading subprocess popen communicate


【解决方案1】:

编辑:对不起,我在最初的回答中对overheating 的范围感到困惑。我删除了答案的第一部分,因为它不再相关。

communicate 将等待进程退出,因此在这种情况下它可能不是您想要的。如果您希望流程继续进行 你可以使用popen.stdin.write("p") 之类的东西。如果您的流程需要,您可能还需要发送“\n”。

此外,如果您对额外的依赖项感到满意,您可能会对设计用于控制交互式进程的 pexpect 模块感兴趣。

【讨论】:

  • 我实际上对 pexpect 没有任何问题,但我发现它在 Windows 上并不能很好地工作。通信确实看起来像阻塞,但程序似乎吹过 stdin.write 并继续运行。
  • 尝试在write 之后立即调用popen.stdin.flush()。或者将bufsize=0 添加到Popen 调用以避免缓冲问题。
  • 该死,我都试过了。单独然后一起。这让我发疯了。
  • Popen 真的是一团糟,尤其是在 Windows 上。尝试添加universal_newlines=True 并发送“p\n”而不是“p”。如果这不起作用,则可能是您在阅读这些行的方式上遇到了某种僵局。尝试调整来自 answer 的代码,看看它是否更适合您。
  • 不幸的是,这正是我正在寻找的东西。在您显示的答案中,它实际上“完成”了打印,并期待某种输入。但是有了这个密码破解器,它就不会等待输入。
【解决方案2】:

一个简单的便携式解决方案是use threads here。没有block buffering issues就够了。

如果检测到过热则读取输出并停止输入(未测试):

#!/usr/bin/env python
from subprocess import Popen, PIPE, CalledProcessError
from threading import Event, Thread

def detect_overheating(pipe, overheating):
    with pipe: # read output here
        for line in iter(pipe.readline, ''): 
            if detected_overheating(line.rstrip('\n')):
                overheating.set()    # overheating
            elif paused: #XXX global
                overheating.clear()  # no longer overheating

process = Popen(args, stdout=PIPE, stdin=PIPE, bufsize=1,
                universal_newlines=True) # enable text mode
overheating = Event() 
t = Thread(target=detect_overheating, args=[process.stdout, overheating])
t.daemon = True # close pipe if the process dies
t.start()
paused = False
with process.stdin: # write input here
    while process.poll() is None:
        if overheating.wait(1): # Python 2.7+
            # overheating
            if not paused:
                process.stdin.write('p\n') # pause
                process.stdin.flush()
                paused = True
        elif paused: # no longer overheating
            pass #XXX unpause here
            paused = False
if process.wait() != 0: # non-zero exit status may indicate failure
    raise CalledProcessError(process.returncode, args)

【讨论】:

  • 不幸的是,这与我发现的其他解决方案相似。它可以很好地打印所有内容,但 stdin.write 仍然无法正常工作。没有错误,直接运行。
  • @themuffinman:“跑过去”是什么意思——孩子收到暂停命令了吗?您是否期望父级中的循环停止?孩子是否在其标准输入(通过管道)上接受 anything ?您可以将任何命令传递给孩子(无论是否同步)?你的操作系统是什么?您确定孩子不会直接读/写终端而不是管道吗? (用信息更新您的问题)
  • 它的标准输入似乎不接受任何内容。我一直在使用 quit 命令进行测试,但什么也没有。它不会抛出任何错误并继续运行。因为程序可以在没有用户输入的情况下继续运行,因为它不等待用户输入,所以我只能在输出特定行时将其传递给标准输入。但还是什么都没有。
  • @themuffinman:你在 Windows 上吗?你能从process.stdout 读到什么吗?如果您的 Python 脚本没有显式打印捕获的输出,您会在屏幕上看到任何输出吗?尽管stdin=PIPE,子进程是否接受手动键盘输入?你能用SendKeys library传递any命令吗?
  • 使用 Windows,一切都打印得很好,异步,线程等。从来没有任何问题。不接受手动键盘输入。我正在研究 SendKeys,但没有看到将它与子进程一起使用的方法。
猜你喜欢
  • 2011-11-26
  • 2010-12-21
  • 2013-05-04
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-18
  • 2015-01-06
相关资源
最近更新 更多