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

ped*_*ram 56 python multithreading wxpython

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

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

我想在我的实现一个'停止'按钮,wx.Frame要求循环线程停止.它不需要立即结束线程,它可以在唤醒后停止循环.

这是我的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)
Run Code Online (Sandbox Code Playgroud)

在我的wxPyhton框架中,我从"开始"按钮调用此函数:

def CheckAsset(self, asset):
        self.count += 1
        thread = PingAssets(self.count, asset, self)
        self.threads.append(thread)
        thread.start()
Run Code Online (Sandbox Code Playgroud)

Jan*_*sky 83

螺纹可停止功能

threading.Thread可以修改函数以允许通过标志停止,而不是子类化.

我们需要一个可运行的函数访问的对象,我们将该标志设置为停止运行.

我们可以使用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()
Run Code Online (Sandbox Code Playgroud)

诀窍是,正在运行的线程可以附加其他属性.该解决方案建立在假设的基础上

  • 该线程具有默认值的属性"do_run" True
  • 驱动父进程可以为已启动的线程分配属性"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.
Run Code Online (Sandbox Code Playgroud)

丸杀 - 使用事件

其他替代方法是使用threading.Event函数参数.默认情况下False,外部进程可以"设置"(to 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()
Run Code Online (Sandbox Code Playgroud)

编辑:我在Python 3.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()
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!帮了我很多 (3认同)

Mik*_*oll 25

之前已经在Stack上询问过这个问题.请参阅以下链接:

基本上你只需要设置一个带有stop函数的线程,该函数设置线程将检查的sentinel值.在你的情况下,你将循环中的东西检查sentinel值以查看它是否已更改,如果有,则循环可能会中断并且线程可能会死亡.


ped*_*ram 12

我在Stack上阅读了其他问题,但我仍然对跨类通信感到困惑.这是我接近它的方式:

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

如何在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()
Run Code Online (Sandbox Code Playgroud)

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

def OnStop(self, e):
        for t in self.threads:
            t.signal = False
Run Code Online (Sandbox Code Playgroud)