Python - 如何实现'可停止'线程?

时间:2017-12-20 18:58:09

标签: multithreading python-3.x class

有一个解决方案已发布here来创建一个可停止的线程。但是,我在理解如何实施此解决方案时遇到了一些问题。

使用代码......

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

如何创建一个运行一个函数的线程,该函数每隔1秒向终端输出“Hello”。 5秒后,我使用.stop()来停止循环函数/线程。

我再次理解如何实现这种停止解决方案的麻烦,这是我到目前为止所做的。

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

上面的代码创建了可以通过testthread.stop()命令停止的线程testthread。据我所知,这只是创建一个空线程...有没有办法我可以创建一个运行funct()的线程,当我使用.stop()时线程将结束。基本上我不知道如何实现StoppableThread类来运行funct()函数作为一个线程。

常规线程函数示例...

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.

3 个答案:

答案 0 :(得分:2)

您在原始示例中使用代码的方式存在一些问题。首先,您没有将任何构造函数参数传递给基础构造函数。这是一个问题,因为正如您在plain-Thread示例中所看到的,构造函数参数通常是必需的。您应该按如下方式重写StoppableThread.__init__

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

由于您使用的是Python 3,因此无需为super提供参数。现在你可以做到

testthread = StoppableThread(target=funct)

这仍然不是最佳解决方案,因为funct使用外部变量testthread来阻止自身。虽然对于像你这样的小例子来说这是好的,但使用像这样的全局变量通常会导致巨大的维护负担而你不想这样做。一个更好的解决方案是为您的特定任务扩展通用StoppableThread类,以便您可以正确访问self

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

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

如果您绝对不想扩展StoppableThread,则可以优先使用任务中的current_thread函数来读取全局变量:

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

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

答案 1 :(得分:0)

受上述解决方案的启发,我针对此问题创建了一个小型库ant。

示例

from ants import worker

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

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

在上面的示例中,do_stuff将在while 1:循环中被调用的单独线程中运行

您还可以触发事件,例如在上面的示例中,将do_stuff.start()替换为do_stuff.start(lambda: time.sleep(5)),每隔5秒就会触发一次

该库是一个非常新的库,正在GitHub https://github.com/fa1k3n/ants.git上进行工作

答案 2 :(得分:0)

我找到了一个可停止线程的实现-它不依赖于您检查它是否应该继续在线程内运行-它“将”异常“注入”包装函数中-只要您不这样做就可以工作像:

which: no docker in (/home/dev/.var/app/io.atom.Atom/data/python/bin:/app/bin:/usr/bin)

绝对值得一看!

请参阅:https://github.com/kata198/func_timeout

也许我将使用这种机制来扩展我的wrapt_timeout_decorator,您可以在这里找到:https://github.com/bitranox/wrapt_timeout_decorator