【问题标题】:How to create a trigger with threading.Timer?如何使用 threading.Timer 创建触发器?
【发布时间】:2015-06-14 04:00:07
【问题描述】:

我上个月才发现python,我根本不是程序员。我正在尝试为电子仪器创建自己的软件。 我实际上需要创建一个触发器,它将每 0.04 毫秒调用一个函数 (如果它是可能的)。我试过这个:

在我的第一个文件 Metronome.py 中:

class Metronome:

    def __init__(self, clip, _matrix):
        self.clip = clip
        self._matrix = _matrix
        self.inc = -1


    def _trigger(self): 
        self.inc = self.inc + 1
        self._matrix.get_button(self.inc, 1).send_value(GREEN_FULL)
        t = threading.Timer(1.0, self._trigger).start()

在第二个文件和一个新类中:

我导入之前的函数:

from Metronome.py import Metronome

我调用前面的函数:

Metronome(self.clip, self._matrix)._trigger()

_trigger 函数中,self._matrix.get_button(self.inc, 1).send_value(GREEN_FULL) 允许我在仪器界面上发送 LED 反馈。 当我启动该程序时,我实际上得到了关于我的仪器的第一个 LED 反馈。但是,其他设置需要 1 秒以上,并且其中一些会同时出现。此外,每次反馈后,下一次的时间都会增加(如 5/10 秒)。我不明白!

【问题讨论】:

  • 我已尝试编辑您的代码以美化问题并使其易于理解,但仍有太多未知数。
  • 请正确格式化代码并说明它是否在另一个类中(否则对self.的引用过多)
  • 对不起,我按你说的做了,这样更好吗?
  • 另外:.py 后缀在 import 语句中是不必要的
  • ehm.. 节拍器是一个类,而不是一个函数。您正在实例化一个 Metronome 类的对象,然后调用它的 _trigger 方法。这很好。但是,根据我之前的问题,您为什么要通过 self. 引用您的 clip_matrix 参数?该调用是在另一个类中进行的,而这些变量是它的属性吗?

标签: python multithreading python-2.7 timer


【解决方案1】:

除了关于如何调用Metronome 类的其他问题(参见上面的cmets),我认为_trigger 方法应该更像:

def _trigger(self):
    while True:
        self.inc += 1
        self._matrix.get_button(self.inc, 1).send_value(GREEN_FULL)
        if (whatever_exit_condition):
            break
        time.sleep(time_interval_in_seconds)

如果没有退出条件,只需删除 if 块。

简而言之:避免在每个周期都创建一个新计时器。 相反,只在您开始调用该方法时创建一个 Timer:

t = threading.Timer(1.0, Metronome(self.clip, self._matrix)._trigger).start()

这是一个关于如何使用计时器的工作示例:

#! /usr/bin/env python
from sys import argv
import time
import threading


def f():
    retry = 0
    while True:
        print "f, retry=", retry
        retry += 1
        if retry > 3:
            break
        time.sleep(2)
    print ("f exited")


if __name__ == "__main__":
    if len(argv) <= 1:
        print "usage: %s num" % (argv[0],)
        exit(1)
    t = threading.Timer(1.0, f)
    t.start()
    for i in range(int(argv[1])):
        time.sleep(1)
        print "main, i=", i

如果你运行它:

python timer.py 10

它输出:

f, retry= 0
main, i= 0
main, i= 1
f, retry= 1
main, i= 2
main, i= 3
f, retry= 2
main, i= 4
main, i= 5
f, retry= 3
f exited
main, i= 6
main, i= 7
main, i= 8
main, i= 9

基本上主线程是活动的并且做他的事情,而定时器线程是通过定时器创建一次并且它继续做它的位(例如在你的情况下向用户发出信号),次数有限(3 ),在每个周期之间睡觉。 我希望现在更清楚了。

【讨论】:

  • 您好!所以我尝试了你所说的,它看起来有效。但是我仍然有一个问题:self._matrix.get_button(self.inc, 1).send_value(GREEN_FULL) 调用仅在循环停止时发送(使用 if 语句)。我认为这是因为缓冲区没有?如何在循环的每个新步骤中发送调用?
  • 嗯.. 那么部分好消息。我假设这些调用在按钮上显示了一些东西,但我忽略了库/架构是什么。这是我能做的一切。
  • 好的,所以我决定立即创建一个线程。所以现在,我不再使用计时器方法了,我使用这个:t = threading.Thread(target=Metronome(self.clip, self._matrix)._trigger, args=()).start() 但是我遇到了一个问题。我删除了while循环来理解它。问题是,如果我删除 time.sleep,按钮会立即亮起(没关系),但如果我让它在超过 2 秒(如 5/6/10 秒)后亮起。另一方面,如果我在没有像 self.metronome._trigger() 这样的新线程的情况下调用 _trigger 方法,那么 time.sleep 就可以了!
  • 我差点忘了,如果我使用 join(),我的主线程会等待(所以它也会冻结)但 time.sleep 运行良好!
猜你喜欢
  • 2014-12-04
  • 2020-09-04
  • 2016-03-06
  • 2010-10-08
  • 1970-01-01
  • 2014-04-07
  • 2015-03-01
  • 1970-01-01
  • 2014-02-02
相关资源
最近更新 更多