V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
sudoy
V2EX  ›  问与答

请问 Python 多线程该如何终止程序?

  •  
  •   sudoy · 61 天前 · 680 次点击
    这是一个创建于 61 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面是代码结构,我的问题是ctrl+c无法终止程序,请老哥们看下有什么办法,搜了很多比如 signal,try 等方法都不适用

    import time
    import threading
    
    
    class Task(threading.Thread):
        def __init__(self, *args, **kwargs):
            super(Task, self).__init__(*args, **kwargs)
            self.daemon = True
    
        def task1(self):
            while True:
                print("starting task1")
                time.sleep(5)
                print("task1 completed!")
    
        def task2(self):
            while True:
                print("starting task2")
                time.sleep(15)
                print("task2 completed!")
    
        def run(self):
            try:
                thread1 = threading.Thread(target=self.task1)
                thread2 = threading.Thread(target=self.task2)
                thread1.start()
                thread2.start()
                thread1.join()
                thread2.join()
            except KeyboardInterrupt:
                print("KeyboardInterrupt has been caught.")
            
    
    if __name__ == "__main__":
        task = Task()
        task.run()
    
    
    第 1 条附言  ·  61 天前
    感谢大家的回复!以下是我整理的解决方案,希望对其他有需要的 V 友有帮助。

    像我这种情况最好是用 `multiprocessing` 而不是 `threading`。因为用`threading`按`ctrl+c`以后需要等最后一个循环执行结束才可以退出。

    参考来源:
    https://stackoverflow.com/questions/11436502/closing-all-threads-with-a-keyboard-interrupthttps://www.geeksforgeeks.org/multiprocessing-python-set-1/#highlighter_806430

    1. 用 `multiprocessing`
    ( )


    2. 如果非要用 `threading`, 如下:
    ( )
    12 条回复    2021-09-28 16:03:22 +08:00
    ipwx
        1
    ipwx   61 天前   ❤️ 1
    1. time.sleep => condition variable.wait(timeout)
    2. self.running = False
    3. while not self.running

    多线程打断不是正确的写法。正确的写法永远是让线程自己退出。
    rationa1cuzz
        2
    rationa1cuzz   61 天前
    你 KeyboardInterrupt 把 ctrl+c 操作 try 捕捉,ctrl+c 自然无法终止程序,在外部终止只能通过 kill 或者 signal 9 终止,非则就只能在程序内部做处理,但是你 while true,不会停下来一直跑的。
    sudoy
        3
    sudoy   61 天前
    @rationa1cuzz 不用多线程的时候即便是 while true 也可以通过 ctrl+c 终止程序的。我现在添加了一个任务,就得用多线程,然而问题就来了,无法终止任务。
    ![img]( )
    plko345
        4
    plko345   61 天前 via Android
    你别捕获 ctrl c 呀
    rationa1cuzz
        5
    rationa1cuzz   61 天前   ❤️ 1
    兄弟,这两行代码就是会捕捉你的 ctrl+c 的操作啊
    try:
    except KeyboardInterrupt:
    你用这代码的目的是啥?
    其次你用 join 会一直等待子线程跑完主进程才会关闭,你要是想 ctrl+c 终止,可以不加 join()方法,或者设置线程为 thread1.daemon =True
    https://docs.python.org/3/library/threading.html?highlight=threading#module-threading
    ipwx
        6
    ipwx   61 天前   ❤️ 1
    @rationa1cuzz 他设了。

    但是后台线程应该让它自己终止,而不应该依赖 daemon = True
    sudoy
        7
    sudoy   61 天前
    @rationa1cuzz 我是想 ctrl+c 以后马上结束所有线程。最后换成用 multiprocessing 实现了我的需求。感谢回复!👍
    rationa1cuzz
        8
    rationa1cuzz   61 天前
    @ipwx 他的 thread1 和 thread2 没有设置吧,只是 task 这个地方是,
    另外,我才发现他这个是线程类里又单独起了两个子线程。
    不应该依赖外部结束线程这个我也同意
    ipwx
        9
    ipwx   61 天前   ❤️ 1
    time.sleep 用楼主你的代码不容易 interrupt,ctrl + c 还要等。而且 Task 这个对象完全没必要做成 Thread 。给你个例子,Ctrl+C 可以直接立刻打断,并且最后一个 task1 completed 和 task2 completed 是会输出的:



    输出:

    starting task1
    starting task2
    task1 completed!
    starting task1
    task2 completed!
    starting task2
    task1 completed!
    starting task1
    task2 completed!
    starting task2
    ^CKeyboardInterrupt has been caught.
    task2 completed!
    task1 completed!
    sudoy
        10
    sudoy   61 天前
    @ipwx 我这边在 Windows 10 下运行您的代码按 ctrl+c 还是无法打断程序哦
    sudoy
        11
    sudoy   61 天前
    @ipwx 问题已经解决了,我把解决方案 append 在这个贴子后面了。感谢回复!
    ykk
        12
    ykk   61 天前
    需要在进程中增加退出条件
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1017 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 23:14 · PVG 07:14 · LAX 15:14 · JFK 18:14
    ♥ Do have faith in what you're doing.