【问题标题】:How to pause and resume a thread using the threading module?如何使用 threading 模块暂停和恢复线程?
【发布时间】:2011-03-16 19:06:12
【问题描述】:

我计划在线程中运行一个很长的进程,否则它将冻结我的 wxpython 应用程序中的 UI。

我正在使用:

threading.Thread(target=myLongProcess).start()

启动线程并且它可以工作,但我不知道如何暂停和恢复线程。我在 Python 文档中查找了上述方法,但找不到它们。

谁能建议我如何做到这一点?

【问题讨论】:

    标签: python multithreading python-multithreading


    【解决方案1】:

    我也做了一些速度测试,设置标志和采取行动的时间在慢速 2 处理器 Linux 机器上快得令人愉悦 0.00002 秒。

    使用set()clear() 事件的线程暂停测试示例:

    import threading
    import time
    
    # This function gets called by our thread.. so it basically becomes the thread init...                
    def wait_for_event(e):
        while True:
            print('\tTHREAD: This is the thread speaking, we are Waiting for event to start..')
            event_is_set = e.wait()
            print('\tTHREAD:  WHOOOOOO HOOOO WE GOT A SIGNAL  : %s' % event_is_set)
            # or for Python >= 3.6
            # print(f'\tTHREAD:  WHOOOOOO HOOOO WE GOT A SIGNAL  : {event_is_set}')
            e.clear()
    
    # Main code
    e = threading.Event()
    t = threading.Thread(name='pausable_thread', 
                         target=wait_for_event,
                         args=(e,))
    t.start()
    
    while True:
        print('MAIN LOOP: still in the main loop..')
        time.sleep(4)
        print('MAIN LOOP: I just set the flag..')
        e.set()
        print('MAIN LOOP: now Im gonna do some processing')
        time.sleep(4)
        print('MAIN LOOP:  .. some more processing im doing   yeahhhh')
        time.sleep(4)
        print('MAIN LOOP: ok ready, soon we will repeat the loop..')
        time.sleep(2)
    

    【讨论】:

    • 为了回答这个问题,您可能需要一个对象 thread_resume = threading.Event(),然后是 thread_resume.set()。在您的线程中,您可以在方便的时候检查 thread_resume.wait()。如果另一个线程调用thread_resume.clear(),该线程将暂停,并在另一个线程调用thread_resume.set()时恢复
    • 这些是我见过的最激动人心的评论和输出字符串。
    • 但是I just set the flag 应该在e.set() innit 之后。
    【解决方案2】:

    我遇到了同样的问题。在线程循环中使用 time.sleep(1800) 来暂停线程执行更有效。

    例如

    MON, TUE, WED, THU, FRI, SAT, SUN = range(7) #Enumerate days of the week
    Thread 1 : 
    def run(self):
            while not self.exit:
                try:
                    localtime = time.localtime(time.time())
                    #Evaluate stock
                    if localtime.tm_hour > 16 or localtime.tm_wday > FRI:
                        # do something
                        pass
                    else:
                        print('Waiting to evaluate stocks...')
                        time.sleep(1800)
                except:
                    print(traceback.format_exc())
    
    Thread 2
    def run(self):
        while not self.exit:
            try:
                localtime = time.localtime(time.time())
                if localtime.tm_hour >= 9 and localtime.tm_hour <= 16:
                    # do something
                    pass
                else:
                    print('Waiting to update stocks indicators...')
                    time.sleep(1800)
            except:
                print(traceback.format_exc())
    

    【讨论】:

      【解决方案3】:

      多处理模块在 Windows 上运行良好。请参阅此处的文档(第一段结尾):

      http://docs.python.org/library/multiprocessing.html

      在 wxPython IRC 频道上,我们有几个人尝试了多处理,他们说它有效。不幸的是,我还没有看到有人写过一个很好的多处理和 wxPython 示例。

      如果你(或这里的其他人)想出一些东西,请将其添加到 wxPython wiki 页面上的线程:http://wiki.wxpython.org/LongRunningTasks

      您可能想查看该页面,因为它有几个使用线程和队列的有趣示例。

      【讨论】:

        【解决方案4】:

        你可以看看Windows API for thread suspension

        据我所知,没有 POSIX/pthread 等价物。此外,我无法确定线程句柄/ID 是否为made available from Python。 Python 也存在潜在问题,因为它的调度是使用本机调度程序完成的,它不太可能期望线程挂起,特别是如果线程在持有 GIL 时挂起,以及其他可能性。

        【讨论】:

          【解决方案5】:

          没有其他线程强制暂停线程的方法(就像其他线程杀死该线程一样)-目标线程必须通过偶尔检查适当的“标志”来合作(threading.Condition 可能是适用于暂停/取消暂停的情况)。

          如果您使用的是 unix-y 平台(基本上除了 windows 之外的任何平台),您可以使用 multiprocessing 而不是 threading -- 那个 更强大,并且可以让您向“其他进程”发送信号; SIGSTOP 应该无条件地暂停一个进程,SIGCONT 继续它(如果你的进程需要在它暂停之前做一些事情,还要考虑 SIGTSTP 信号,其他进程可以捕捉到它来执行这种预暂停职责。(可能有一些方法可以在 Windows 上获得相同的效果,但我不了解它们(如果有的话)。

          【讨论】:

          • 不幸的是,我的目标是 Windows,所以我认为我不能使用多处理。我不希望一个线程暂停另一个线程,我只想向线程发送一条消息,告诉它自己暂停(或者这与告诉一个线程暂停另一个线程是一样的吗?),可以通过调整线程类?
          • “发送消息”可以从字面上通过队列来完成,但是(正如我所说)对于这种带有条件的情况更实际。但是目标线程必须定期检查条件(或队列)才能接收“消息”:您无法“强制”它“接收消息”,您必须编码 以这种方式显式(可能带有循环)。其他线程无法强制使线程“接收针对它的消息”,以您似乎更喜欢的术语投射我的 A 的第一句话。顺便说一句,Windows 确实有一个 SuspendThread API(续)
          • 对于特定于 Windows 的解决方案,请参阅 msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx -- 您可以使用 ctypessourceforge.net/projects/pywin32 直接从 Python 调用 Windows API。
          【解决方案6】:

          您可以使用信号:http://docs.python.org/library/signal.html#signal.pause

          为避免使用信号,您可以使用令牌传递系统。如果您想从主 UI 线程暂停它,您可能只需要使用 Queue.Queue 对象与其通信。

          只需弹出一条消息,告诉线程休眠一段时间到队列中。

          或者,您可以简单地将令牌从主 UI 线程连续推送到队列中。工作人员应该每 N 秒(0.2 或类似的时间)检查一次队列。当没有令牌出队时,工作线程将阻塞。当您希望它重新开始时,只需再次开始将令牌从主线程推送到队列中。

          【讨论】:

          • 不,你不能向线程发送信号——只能向进程发送信号!而signal.pause 仅表示调用进程休眠,直到收到信号——对 OP 的请求没有用处。请参阅我的答案以了解正确的方法。
          • @Alex - 感谢您的澄清。我的反应的信号部分是事后的想法..欢呼:)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-04-01
          • 1970-01-01
          • 2016-03-24
          • 1970-01-01
          • 2014-05-29
          • 2011-08-02
          相关资源
          最近更新 更多