Python,使用多线程退出带有用户输入的 While 循环(ctrl+c 不起作用)

Python, exit While loop with User Input using multithreading (cntrl+c wont work)

我有一个系统利用率函数,monitor(),我想 运行 直到用户通过输入数字零 exit_collecting() 来停止它。我不想突然结束程序,因为那样会否定后续代码。
我尝试 运行 使用多线程 exit_collecting() 和 monitor() 来连接这两个函数,让 monitor() 运行 直到用户通过键入零停止它,exit_collecting( ).

我下面的代码抛出了一堆回溯。我是这方面的新手,任何想法,任何帮助都会很棒。谢谢你。顺便说一句,我最初尝试使用“尝试使用 KeyboardInterrupt 除外”,但是当使用 IDLE (Spyder) 时,ctrl-c 组合不起作用(它分配给“复制”),ctrl-c 在我时不起作用运行 它来自 Linux 中的控制台。

def exit_collecting():
    try:
        val = int(input("Type 0 to exit data collection mode"))
        if val == 0:
            flag = 0
    except:
        print(val,"typo, enter 0 to exit data collection mode")


def monitor():
    import time
    import psutil
    flag = 1
    while flag > 0:
        time.sleep(1)
        print("cpu usuage:",psutil.cpu_percent())
        

from multiprocessing import Process
p1 = Process(target=exit_collecting)
p1.start()
p2 = Process(target=monitor)    
p2.start()
p1.join()
p2.join()

你的多进程版本注定要失败,因为每个进程都有自己的内存space并且不共享相同的变量flag。它可以通过多处理来完成,但您必须使用使用共享内存的 flag 的实现。

使用线程的解决方案要简单得多,只要进行一处更改,您的代码就应该可以正常工作。您忽略了将 flag 声明为全局。这是确保函数 exit_collectingmonitor 修改同一个变量所必需的。如果没有这些声明,每个函数都会修改一个 local flag 变量:

def exit_collecting():
    global flag
    try:
        val = int(input("Type 0 to exit data collection mode"))
        if val == 0:
            flag = 0
    except:
        print(val,"typo, enter 0 to exit data collection mode")


def monitor():
    global flag
    import time
    import psutil
    flag = 1
    while flag > 0:
        time.sleep(1)
        print("cpu usuage:",psutil.cpu_percent())


from threading import Thread
p1 = Thread(target=exit_collecting)
p1.start()
p2 = Thread(target=monitor)
p2.start()
p1.join()
p2.join()

但是也许可以通过将monitor线程变成daemon线程来简化上面的代码,也就是当所有非daemon都自动终止的线程线程终止(如当前所写,函数 monitor 似乎可以在处理过程中的任何时候终止)。但无论如何,主线程都可以执行 exit_collecting 正在执行的功能。现在没有理由不能使用键盘中断(只要您在主线程中等待 input 语句):

def monitor():
    import time
    import psutil
    while True:
        time.sleep(1)
        print("cpu usuage:",psutil.cpu_percent())


from threading import Thread
p = Thread(target=monitor)
p.daemon = True
p.start()
try:
    input("Input enter to halt (or ctrl-C) ...")
except KeyboardInterrupt:
    pass         
"""
When the main thread finishes all non-daemon threads have completed
and therefore the monitor thread will terminate.
"""

更新:允许monitor线程正常终止并允许键盘中断

我已经简化了逻辑 a 但只是为了使用一个简单的全局标志,terminate_flag,最初是 False,它只被 monitor 线程读取,因此没有将其明确声明为全局:

terminate_flag = False

def monitor():
    import time
    import psutil
    while not terminate_flag:
        time.sleep(1)
        print("cpu usuage:", psutil.cpu_percent())


from threading import Thread

p = Thread(target=monitor)
p.start()
try:
    input('Hit enter or ctrl-c to terminate ...')
except KeyboardInterrupt:
    pass
terminate_flag = True # tell monitor it is time to terminate
p.join() # wait for monitor to gracefully terminate