如何终止/中断/中止Python console/sys.stdin readline()?

2023-12-07

在线程中,我有一个循环从用户控制台读取输入。主线程正忙于 Tkinter mainloop()。我如何终止这个程序?

while True:
    ln = sys.stdin.readline()
    try:
        ln = ln[:-1]  # Remove LF from line
        if len(ln)==0: continue  # Ignore blank lines
        ...and so on

主线程调用 startGUI(),其中包含 tk.mainloop() 调用。当我按下窗口上的 X 关闭按钮(这是 Linux)时,Tkinter 关闭窗口并且 mainloop() 返回。然后,我尝试关闭 stdin,希望 sys.stdin 将关闭并导致 sys.stdin.readline() 以良好的 EOF 终止,从而允许我的 stdinLoop 线程终止。

# Start up the GUI window
startGUI()  # Doesn't return until GUI window is closed, tk.mainloop is called here
#
# Wait for stdinLoop thread to finish
sys.stdin.close()  # Hopefully cause stdinTh to close
print("waiting for stdinTh to join")
stdinTh.join()
print("joined stdinTh")

sys.stdin.realine() 在 sys.stdin.close() 之后永远不会返回。 (stdinTh.join() 用于同步关闭。)

我认为 Python readline() 正在做一些事情clever(在称为 NetCommand 的东西中)当标准输入关闭时不会干净地返回。

Python 是否认为是evil既要有 Tkinter GUI 又要交互地使用 stdin?

我尝试使用 sys.stdin.read(1),但似乎缓冲了一行并返回整行——而不是像我认为的 read(1) 那样读取一个字节/字符。


使线程成为将自动终止的守护线程

启动标准输入读取线程daemon=True。当主线程终止时,它将自动终止。您不需要显式地对 stdin 执行任何操作。 (您也没有机会在标准输入读取线程中进行清理。)例如:

stdinTh = threading.Thread(target=stdinLoop, name="stdinTh")
stdinTh.daemon = True
stdinTh.start()

如果您不能或不想使用守护线程

sys.stdin.readline()最终归结为阻塞read()系统调用。

read() on stdin不返回时stdin关闭了。我不确定你为什么期望它。这不是 Python 特有的行为。至少在我的 Linux/glibc 系统上,C 语言中也会发生同样的情况。

你可以突破阻碍read()通过发送信号(例如SIGUSR1) 到被阻塞的线程。在C中,你可以使用pthread_kill()为了那个原因。 Python 没有提供一种简单的方法来做到这一点,这是有充分理由的;但如果你坚持的话,你可以做它与ctypes.

但更清洁/更安全的方法是使用select.select从中读取either stdin or线程间通信管道,以先可用者为准:

import os, select, sys, threading, time

def printer_loop(quit_pipe):
    while True:
        sys.stdout.write("Say something: ")
        sys.stdout.flush()
        (readable, _, _) = select.select([sys.stdin, quit_pipe], [], [])
        if quit_pipe in readable:
            print("Our time is up!")
            break
        # This is not exactly right, because `sys.stdin` could become
        # ready for reading before there's a newline on there, so
        # `readline` could still block. Ideally you would do some
        # custom buffering here.
        line = sys.stdin.readline()
        print("You said: '%s' - well said!" % line.strip())

def main():
    print("Starting thread...")
    (pipe_read, pipe_write) = os.pipe()
    thread = threading.Thread(target=printer_loop, args=(pipe_read,))
    thread.start()
    time.sleep(5)
    print("Interrupting thread...")
    os.write(pipe_write, b'.')
    print("Joining thread...")
    thread.join()
    print("All done!...")

if __name__ == '__main__':
    main()

这不能移植到 Windows,您不能select() on sys.stdin.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何终止/中断/中止Python console/sys.stdin readline()? 的相关文章

随机推荐