首页 > 解决方案 > 如何在类中使用充当倒数计时器的线程?

问题描述

我想定义一个包含id,status和的对象countdown timer。一旦我实例化了这个对象,倒数计时器应该立即启动。

下面是我创建一个类的代码,该类中定义了倒数计时器的非线程版本

import time
import sys
from threading import Timer

class UserTimer:
    def __init__(self, id=None, current_status=None):
        self.id = id
        self.current_status = current_status
        self.timeout()

    def timeout(self):
        print("timeout started for", self.id)
        timeout_limit = 150
        seconds = 0
        while True:
            try:
                if seconds == timeout_limit:
                    print("countdown over for", self.id)
                    break
                time.sleep(1)
                seconds += 1
            except KeyboardInterrupt, e:
                break

下面是如何实例化它

params1 = {'id': "test@hello.com", 'current_status': "success"}
params2 = {'id': "test2@hello.com", 'current_status': "success"}
user1 = UserTimer(**params1)
user2 = UserTimer(**params2)

这里的问题是,当这个程序运行时,它将实例化第一个对象 ( user1),并且由于函数的原因,它会在实例化第二个对象 ( )time.sleep()之前等待给定的持续时间user2

因此,我随后查找并发现 python 线程在这种情况下很有帮助,因为线程将独立运行并且不会阻塞代码的进程。

所以这就是我更改下面代码的方式

class UserTimer:
    def __init__(self, id=None, current_status=None):
        self.id = id
        self.current_status = current_status

    def timeout(self):
        print("time over for", self.id)


    t = Timer(150, timeout)
    t.start()


params1 = {'id': "test@hello.com", 'current_status': "success"}
params2 = {'id': "test2@hello.com", 'current_status': "success"}
user1 = UserTimer(**params1)
user2 = UserTimer(**params2)

现在两个对象同时实例化,但问题是一旦给定持续时间结束,就会出现以下错误

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 1073, in run
    self.function(*self.args, **self.kwargs)
TypeError: timeout() takes exactly 1 argument (0 given)

这是因为它看到了self它不期望的关键字。但我需要,self因为我需要转储有关用户对象的一些信息。如果我删除self,那么它运行良好。

我是否以错误的方式在类中定义线程?我想要的是能够实例化具有自己的倒数计时器的多个对象。

此外,我还应该能够通过执行类似的操作来重置倒数计时器user1.reset_timer = True

我在这里做错了什么?

标签: pythonmultithreadingooptimer

解决方案


我从你的代码中得到了一个与你不同的错误:

TypeError: timeout() missing 1 required positional argument: 'self'

线索是提到self这是由以下原因引起的:

    t = Timer(150, timeout)
    t.start()

您在 的类主体中UserTimer,这意味着它在定义类时执行(并且self尚未创建实例)。

解决这个问题的一个简单方法是通过定义一个__call__()方法(并在正确的时间调用它)使类的实例可调用。这就是我的意思:

import time
import sys
from threading import Timer


class UserTimer:
    def __init__(self, id=None, current_status=None, interval=5):
        self.id = id
        self.current_status = current_status
        self.interval = interval

    def timeout(self):
        print("time over for", self.id)

    def __call__(self):
        self.timer_thread = Timer(self.interval, self.timeout)
        self.timer_thread.start()

    def cancel(self):
        try:
            self.timer_thread.cancel()
        except AttributeError:
            raise RuntimeError("'UserTimer' object not started.")


params1 = dict(id="test@hello.com", current_status="success")
params2 = dict(id="test2@hello.com", current_status="success", interval=6)
user1 = UserTimer(**params1)
user1()  # Start Timer.
user2 = UserTimer(**params2)
user2()  # Start Timer.

我还cancel()根据您的要求添加了该方法,并使时间间隔成为一个易于更改的变量,而不是将其硬编码到类的主体中。


推荐阅读