Python - How can I implement a 'stoppable' thread?

笑着哭i 提交于 2019-12-11 14:56:56

问题


There is a solution posted here to create a stoppable thread. However, I am having some problems understanding how to implement this solution.

Using the code...

import threading

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def stopped(self):
        return self._stop_event.is_set()

How can I create a thread that runs a function that prints "Hello" to the terminal every 1 second. After 5 seconds I use the .stop() to stop the looping function/thread.

Again I am having troubles understanding how to implement this stopping solution, here is what I have so far.

import threading
import time

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def stopped(self):
        return self._stop_event.is_set()

def funct():
    while not testthread.stopped():
        time.sleep(1)
        print("Hello")

testthread = StoppableThread()
testthread.start()
time.sleep(5)
testthread.stop()

Code above creates the thread testthread which can be stopped by the testthread.stop() command. From what I understand this is just creating an empty thread... Is there a way I can create a thread that runs funct() and the thread will end when I use .stop(). Basically I do not know how to implement the StoppableThread class to run the funct() function as a thread.

Example of a regular threaded function...

import threading
import time

def example():
    x = 0
    while x < 5:
        time.sleep(1)
        print("Hello")
        x = x + 1

t = threading.Thread(target=example)
t.start()
t.join()
#example of a regular threaded function.

回答1:


There are a couple of problems with how you are using the code in your original example. First of all, you are not passing any constructor arguments to the base constructor. This is a problem because, as you can see in the plain-Thread example, constructor arguments are often necessary. You should rewrite StoppableThread.__init__ as follows:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._stop_event = threading.Event()

Since you are using Python 3, you do not need to provide arguments to super. Now you can do

testthread = StoppableThread(target=funct)

This is still not an optimal solution, because funct uses an external variable, testthread to stop itself. While this is OK-ish for a tiny example like yours, using global variables like that normally causes a huge maintenance burden and you don't want to do it. A much better solution would be to extend the generic StoppableThread class for your particular task, so you can access self properly:

class MyTask(StoppableThread):
    def run(self):
        while not self.stopped():
            time.sleep(1)
            print("Hello")

testthread = MyTask()
testthread.start()
time.sleep(5)
testthread.stop()

If you absolutely do not want to extend StoppableThread, you can use the current_thread function in your task in preference to reading a global variable:

def funct():
    while not current_thread().stopped():
        time.sleep(1)
        print("Hello")

testthread = StoppableThread(target=funct)
testthread.start()
sleep(5)
testthread.stop()



回答2:


Inspired by above solution I created a small library, ants, for this problem.

Example

from ants import worker

@worker
def do_stuff():
    ...
    thread code
    ...

do_stuff.start()
...
do_stuff.stop()

In above example do_stuff will run in a separate thread being called in a while 1: loop

You can also have triggering events , e.g. in above replace do_stuff.start() with do_stuff.start(lambda: time.sleep(5)) and you will have it trigger every 5:th second

The library is very new and work is ongoing on GitHub https://github.com/fa1k3n/ants.git




回答3:


I found some implementation of a stoppable thread - and it does not rely that You check if it should continue to run inside the thread - it "injects" an exception into the wrapped function - that will work as long as You dont do something like :

while True: 
    try: 
        do something
    except:
        pass

definitely worth looking at !

see : https://github.com/kata198/func_timeout

maybe I will extend my wrapt_timeout_decorator with such kind of mechanism, which You can find here : https://github.com/bitranox/wrapt_timeout_decorator



来源:https://stackoverflow.com/questions/47912701/python-how-can-i-implement-a-stoppable-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!