如何在Python中停止循环线程?

2024-03-29 10:40:49 发布

您现在位置:Python中文网/ 问答频道 /正文

告诉循环线程停止循环的正确方法是什么?

我有一个相当简单的程序,它在单独的threading.Thread类中ping指定的主机。在这个类中,它睡眠60秒,然后再次运行,直到应用程序退出。

我想在我的wx.Frame中实现一个“Stop”按钮来请求循环线程停止。它不需要马上结束线程,只要它醒来就可以停止循环。

这是我的threading类(注意:我还没有实现循环,但它可能属于PingAssets中的run方法)

class PingAssets(threading.Thread):
    def __init__(self, threadNum, asset, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.asset = asset

    def run(self):
        config = controller.getConfig()
        fmt = config['timefmt']
        start_time = datetime.now().strftime(fmt)
        try:
            if onlinecheck.check_status(self.asset):
                status = "online"
            else:
                status = "offline"
        except socket.gaierror:
            status = "an invalid asset tag."
        msg =("{}: {} is {}.   \n".format(start_time, self.asset, status))
        wx.CallAfter(self.window.Logger, msg)

在我的wxPyhton框架中,有一个从开始按钮调用的函数:

def CheckAsset(self, asset):
        self.count += 1
        thread = PingAssets(self.count, asset, self)
        self.threads.append(thread)
        thread.start()

Tags: 方法selfdefstatusassetwindow线程按钮
3条回答

这是以前在堆栈上问过的问题。请参阅以下链接:

基本上,您只需要使用一个stop函数来设置线程,该函数设置线程将检查的sentinel值。在您的例子中,您将让something在您的循环中检查sentinel值,看看它是否更改了,如果更改了,循环可能会中断,线程可能会死掉。

螺纹可停止功能

可以修改函数以允许 停在旗子旁边。

我们需要一个对象,可以访问running函数,并将标志设置为stop running。

我们可以使用threading.currentThread()对象。

import threading
import time


def doit(arg):
    t = threading.currentThread()
    while getattr(t, "do_run", True):
        print ("working on %s" % arg)
        time.sleep(1)
    print("Stopping as you wish.")


def main():
    t = threading.Thread(target=doit, args=("task",))
    t.start()
    time.sleep(5)
    t.do_run = False
    t.join()

if __name__ == "__main__":
    main()

诀窍是,正在运行的线程可以附加其他属性。解决方案构建 基于假设:

  • 线程具有默认值为True的属性“do_run”
  • 驱动父进程可以将属性“do_run”分配给启动的线程False

运行代码,我们得到以下输出:

$ python stopthread.py                                                        
working on task
working on task
working on task
working on task
working on task
Stopping as you wish.

使用避孕药事件

另一种选择是使用threading.Event作为函数参数。它是由 默认值为False,但是外部进程可以“设置”(设置为True),函数可以 使用wait(timeout)函数了解它。

我们可以在零超时的情况下wait,但我们也可以将其用作睡眠计时器(下面使用)。

def doit(stop_event, arg):
    while not stop_event.wait(1):
        print ("working on %s" % arg)
    print("Stopping as you wish.")


def main():
    pill2kill = threading.Event()
    t = threading.Thread(target=doit, args=(pill2kill, "task"))
    t.start()
    time.sleep(5)
    pill2kill.set()
    t.join()

编辑:我在Python3.6中尝试过。stop_event.wait()阻止事件(以及while循环)直到释放。它不返回布尔值。而使用stop_event.is_set()则有效。

一丸多线停

如果我们必须停止多个线程,那么可以更好地看到药丸的优势 立刻,就像一颗药丸对所有人都有效一样。

doit根本不会改变,只有main处理线程有点不同。

def main():
    pill2kill = threading.Event()
    tasks = ["task ONE", "task TWO", "task THREE"]

    def thread_gen(pill2kill, tasks):
        for task in tasks:
            t = threading.Thread(target=doit, args=(pill2kill, task))
            yield t

    threads = list(thread_gen(pill2kill, tasks))
    for thread in threads:
        thread.start()
    time.sleep(5)
    pill2kill.set()
    for thread in threads:
        thread.join()

我读了Stack上的其他问题,但在跨类通信方面还是有点困惑。以下是我如何接近它:

我使用一个列表来保存wxFrame类的__init__方法中的所有线程:self.threads = []

按照How to stop a looping thread in Python?中的建议,在初始化线程类时,我在线程类中使用设置为True的信号。

class PingAssets(threading.Thread):
    def __init__(self, threadNum, asset, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.asset = asset
        self.signal = True

    def run(self):
        while self.signal:
             do_stuff()
             sleep()

我可以通过遍历线程来停止这些线程:

def OnStop(self, e):
        for t in self.threads:
            t.signal = False

相关问题 更多 >