如何在Python中停止循环线程? [英] How to stop a looping thread in Python?

查看:953
本文介绍了如何在Python中停止循环线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What's the proper way to tell a looping thread to stop looping?

我有一个相当简单的程序,可以在单独的threading.Thread类中对指定的主机执行ping操作.在此类中,它休眠60秒,然后再次运行,直到应用程序退出.

I have a fairly simple program that pings a specified host in a separate threading.Thread class. In this class it sleeps 60 seconds, the runs again until the application quits.

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

I'd like to implement a 'Stop' button in my wx.Frame to ask the looping thread to stop. It doesn't need to end the thread right away, it can just stop looping once it wakes up.

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

Here is my threading class (note: I haven't implemented looping yet, but it would likely fall under the run method in PingAssets)

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框架中,我从开始"按钮调用了此功能:

And in my wxPyhton Frame I have this function called from a Start button:

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

推荐答案

线程可停止函数

代替子类,可以修改函数以允许 停下一个标志.

Threaded stoppable function

Instead of subclassing threading.Thread, one can modify the function to allow stopping by a flag.

我们需要一个可通过运行功能访问的对象,将其设置为停止运行.

We need an object, accessible to running function, to which we set the flag to 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()

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

The trick is, that the running thread can have attached additional properties. The solution builds on assumptions:

  • 该线程具有默认值True
  • 的属性"do_run"
  • 驱动父进程可以将启动属性"do_run"分配给False.
  • the thread has a property "do_run" with default value True
  • driving parent process can assign to started thread the property "do_run" to False.

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

Running the code, we get following output:

$ 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)函数了解它.

Pill to kill - using Event

Other alternative is to use threading.Event as function argument. It is by default False, but external process can "set it" (to True) and function can learn about it using wait(timeout) function.

我们可以将wait设置为零超时,但是我们也可以将其用作睡眠计时器(以下使用).

We can wait with zero timeout, but we can also use it as the sleeping timer (used below).

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()

我在Python 3.6中进行了尝试. stop_event.wait()阻止事件(以及while循环),直到释放为止.它不返回布尔值.改为使用stop_event.is_set().

I tried this in Python 3.6. stop_event.wait() blocks the event (and so the while loop) until release. It does not return a boolean value. Using stop_event.is_set() works instead.

如果我们必须停止多个线程,则可以更好地看到杀死药丸的优势 一次,因为一粒药将对所有人有用.

Advantage of pill to kill is better seen, if we have to stop multiple threads at once, as one pill will work for all.

doit根本不会改变,只有main处理线程的方式有所不同.

The doit will not change at all, only the main handles the threads a bit differently.

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()

这篇关于如何在Python中停止循环线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆