python - 终止进程会打破Python的诅咒

标签 python python-multiprocessing python-curses

使用python多处理和curses,终止进程似乎会干扰curses显示。
例如,在下面的代码中,为什么终止进程会阻止curses显示文本? (按a后按b)
更准确地说,似乎不仅字符串“hello”不再显示,而且整个curses窗口也不再显示。

import curses
from multiprocessing import Process
from time import sleep

def display(stdscr):
    stdscr.clear()
    curses.newwin(0,0)
    stdscr.timeout(500)
    p = None
    while True:
        stdscr.addstr(1, 1, "hello")
        stdscr.refresh()
        key = stdscr.getch()
        if key == ord('a') and not p:
            p = Process(target = hang)
            p.start()
        elif key == ord('b') and p:
            p.terminate()

def hang():
    sleep(100)

if __name__ == '__main__':
    curses.wrapper(display)

我在 GNU/Linux 下运行 python 3.6。

编辑:
我仍然能够使用这个不调用 sleep() 的更精简的版本进行重现。现在只需按“a”就会触发该错误。

import curses
from multiprocessing import Process

def display(stdscr):
    stdscr.clear()
    curses.newwin(0,0)
    stdscr.timeout(500)
    p = None
    while True:
        stdscr.addstr(1, 1, "hello")
        stdscr.refresh()
        key = stdscr.getch()
        if key == ord('a') and not p:
            p = Process(target = hang)
            p.start()
            p.terminate()

def hang():
    while True:
        temp = 1 + 1

if __name__ == '__main__':
    curses.wrapper(display)

最佳答案

以下代码有效:

import curses
from multiprocessing import Process

p = None
def display(stdscr):
    stdscr.clear()
    curses.newwin(0,0)
    stdscr.timeout(500)
    while True:
        stdscr.addstr(1, 1, "hello")
        stdscr.refresh()
        key = stdscr.getch()
        if key == ord('a') and not p:
            p.start()
            p.terminate()

def hang():
    while True:
        temp = 1 + 1

if __name__ == '__main__':
    p = Process(target = hang)
    curses.wrapper(display)

我创建了一个新的Process在使用 curses.wrapper() 初始化 UI 之前。好吧,为什么这有效?为此我们必须知道如何Proccess工作原理以及当您调用 Process(target = hang) 时它到底做了什么:

fork

The parent process uses os.fork() to fork the Python interpreter. The child process, when it begins, is effectively identical to the parent process. All resources of the parent are inherited by the child process. Note that safely forking a multithreaded process is problematic.

Available on Unix only. The default on Unix.

现在,它告诉我们什么?你在哪里创建一个新的Processes当您已经创建了 curses屏幕。 curses.wrapper() 是什么意思?做什么?

Before calling func, wrapper() turns on cbreak mode, turns off echo, enables the terminal keypad, and initializes colors if the terminal has color support. On exit (whether normally or by exception) it restores cooked mode, turns on echo, and disables the terminal keypad.

好的,我们有一个新创建的子进程,它拥有与其父进程完全相同的资源。当您调用terminate()时为了杀死 child ,它会释放所有资源,包括诅咒包装器。它会恢复之前的终端设置,从而破坏您的 UI。

要解决此问题,您必须以不同的方式实现您的程序。事先创建一个新进程,使用IPC要与您的进程通信,请使用 Process Pools如果您需要多个进程,ThreadingThread Pools如果您有 IO 绑定(bind)任务。

关于python - 终止进程会打破Python的诅咒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44677774/

相关文章:

python - 时间戳减法必须具有相同的时区或没有时区,但它们都是 UTC

python - 正则表达式匹配不适用于 Pyteomics 解析器的简单字符串

python - 连接两个具有共同、重复索引的 Pandas 数据框,而不进行笛卡尔积

python - 为什么 Linux 可以在多进程中接受套接字?

python - 意外的诅咒前/背景 256 色 init_pair'ing

python - 在右下角调用 addch 时 curses 失败

python - 在 python 中解码编码的 JSON 结果

python - 如何使用具有多个参数的函数运行多处理 python 请求

python - 断言错误 : can only start a process object created by current process

Python 诅咒、线程 : Output thread reports a lagging value for global variable