如何终止/中断/中止Python控制台/sys.stdin readline()? [英] How do you terminate/break/abort a Python console/sys.stdin readline()?

查看:1213
本文介绍了如何终止/中断/中止Python控制台/sys.stdin readline()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In thread, I have a loop that reads input from the user console. The main thread is busy with a Tkinter mainloop(). How do I terminate this program?

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()调用.当我按下窗口(这是Linux)上的X关闭按钮时,Tkinter关闭窗口,并且mainloop()返回.然后,我尝试关闭stdin,希望sys.stdin将关闭并导致sys.stdin.readline()将以一个不错的EOF终止,从而允许我的stdinLoop线程终止.

The main thead calls startGUI() which contains a tk.mainloop() call. When I press the X close button on the window (this is Linux), Tkinter closes the window and mainloop() returns. I then try to close stdin hoping that sys.stdin will close and cause sys.stdin.readline() will terminate with a nice EOF allowing my stdinLoop thread terminate.

# 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()用于同步关闭.)

The sys.stdin.realine() never returns after the sys.stdin.close(). (The stdinTh.join() was there to synchronize the closing.)

我认为Python readline()正在做聪明(在称为NetCommand的事情中),当关闭stdin时,它不会干净地返回.

I think Python readline() is doing something clever (in something called NetCommand) that doesn't return cleanly when stdin is closed.

Python认为同时拥有Tkinter GUI和交互使用stdin是 evil 吗?

Does Python think it is evil to have both a Tkinter GUI and use stdin interactively?

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

I tried using sys.stdin.read(1), but is seems buffer up a line and returns the whole line -- rather than reading one byte/char as I thought a read(1) would.

推荐答案

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

通过 daemon=True .当主线程终止时,它将自动终止.您无需显式地使用stdin进行任何操作. (您也没有机会在stdin读取线程中进行清理.)例如:

Make the thread a daemon thread that will be terminated automatically

Start the stdin-reading thread with daemon=True. It will then automatically terminate when the main thread terminates. You don’t need to do anything with stdin explicitly. (You also don’t get a chance to clean up in the stdin-reading thread.) For example:

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

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

sys.stdin.readline()最终归结为一个受阻的 read() 系统调用.

If you can’t or don’t want to use a daemon thread

sys.stdin.readline() eventually boils down to a blocking read() system call.

read()不返回.我不确定为什么会这样.这不是特定于Python的行为.至少在我的Linux/glibc系统上,在C语言中也会发生同样的情况.

read() on stdin does not return when stdin is closed. I’m not sure why you expect it to. This is not Python-specific behavior. At least on my Linux/glibc system, the same happens in C.

您可以通过向被阻塞的线程发送信号(例如SIGUSR1)来突破阻塞的read().在C语言中,您可以使用 pthread_kill() . Python并没有提供一种简便的方法来执行此操作,这是有充分理由的.但是如果您坚持要使用ctypes 做到这一点.

You can break out of a blocking read() by sending a signal (such as SIGUSR1) to the blocked thread. In C, you could use pthread_kill() for that. Python does not provide an easy way to do this, and for good reason; but if you insist, you can do it with ctypes.

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

But a cleaner/safer approach is to use select.select to read from either stdin or an inter-thread communication pipe, whichever is available first:

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,而在sys.stdin上则不能select().

This is not portable to Windows, where you can’t select() on sys.stdin.

这篇关于如何终止/中断/中止Python控制台/sys.stdin readline()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆