终止进程会破坏python curses [英] Terminating a process breaks python curses

查看:151
本文介绍了终止进程会破坏python curses的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using python multiprocessing and curses, it appears that terminating a Process interferes with curses display.
For example, in the following code, why does terminating the process stops curses from displaying the text ? (pressing b after pressing a)
More precisely, it seems that not only the string "hello" is not displayed anymore but also the whole curses window.

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.

I'm running python 3.6 under GNU/Linux.


我仍然可以使用这个更精简的版本(不调用sleep())进行重现.现在只需按"a"即可触发该错误.

Edit :
I'm still able to reproduce with this more stripped down version which doesn't call sleep(). Now just pressing "a" triggers the bug.

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)

在使用curses.wrapper()初始化UI之前,我创建了一个新的Process.好吧,为什么这行得通?为此,我们必须知道过程的工作方式以及调用Process(target = hang)时的确切功能:

I created a new Process before initializing the UI using curses.wrapper(). Okay, why does this work? For this we must know how Proccess works and what exactly it does when you call Process(target = hang):

叉子

父进程使用os.fork()派生Python解释器.子进程开始时实际上与父进程相同.父进程的所有资源均由子进程继承.请注意,安全地分叉多线程进程是有问题的.

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.

仅在Unix上可用. Unix上的默认设置.

Available on Unix only. The default on Unix.

现在,它告诉我们什么?当您已经创建了curses屏幕时,您将在其中创建新的Processes. curses.wrapper()有什么作用?

Now, what does it tell us? You where creating a new Processes when you already created a curses screen. What does curses.wrapper() do?

在调用func之前,wrapper()打开cbreak模式,关闭echo,启用终端键盘,并在终端支持颜色的情况下初始化颜色.退出时(无论是正常还是异常),它都将恢复烹饪模式,打开回显,并禁用终端键盘.

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()杀死孩子时,它将释放所有资源,包括curses包装器.它会还原以前的终端设置,因此会破坏您的用户界面.

Okay, we have a newly created child process that has the exact same resources as its parent. When you call terminate() to kill the child, it frees all resources, including the curses wrapper. It restores the previous terminal settings and therefore breaks your UI.

要解决此问题,您必须以不同的方式实现您的程序.预先创建一个新流程,使用 IPC 要与您的流程进行通信,请使用流程池如果您需要多个进程,请线程

To fix this you have to implement your program differently. Create a new process beforehand, use IPC to communicate with your process, use Process Pools if you need multiple processes, Threading or Thread Pools if you have IO bound tasks.

这篇关于终止进程会破坏python curses的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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