为了账号安全,请及时绑定邮箱和手机立即绑定

如何在python中定期运行函数

/ 猿问

如何在python中定期运行函数

眼眸繁星 2019-12-06 15:50:04

我有一个简单的节拍器运行,由于某种原因,当它以较低的bpm时就可以了,但是以较高的bpms时则不一致且不稳定。我不知道怎么回事。我想尝试使用一些东西定期运行它。有没有办法做到这一点?


这是我的代码:


class thalam():

    def __init__(self,root,e):

        self.lag=0.2

        self.root=root

        self.count=0

        self.thread=threading.Thread(target=self.play)

        self.thread.daemon=True

        self.tempo=60.0/120

        self.e=e

        self.pause=False

        self.tick=open("tick.wav","rb").read()

        self.count=0

        self.next_call = time.time()

    def play(self):

        if self.pause:

            return

        winsound.PlaySound(self.tick,winsound.SND_MEMORY)

        self.count+=1

        if self.count==990:

            self.thread=threading.Thread(target=self.play)

            self.thread.daemon=True

            self.thread.start()

            return


        self.next_call+=self.tempo

        new=threading.Timer(self.next_call-time.time(),self.play)

        new.daemon=True

        new.start()

    def stop(self):

        self.pause=True

        winsound.PlaySound(None,winsound.SND_ASYNC)

    def start(self):

        self.pause=False

    def settempo(self,a):

        self.tempo=a

class Metronome(Frame):

    def __init__(self,root):

        Frame.__init__(self,root)

        self.first=True

        self.root=root

        self.e=Entry(self)

        self.e.grid(row=0,column=1)

        self.e.insert(0,"120")

        self.play=Button(self,text="Play",command=self.tick)

        self.play.grid(row=1,column=1)

        self.l=Button(self,text="<",command=lambda:self.inc("l"))

        self.l.grid(row=0,column=0)

        self.r=Button(self,text=">",command=lambda:self.inc("r"))

        self.r.grid(row=0,column=2)

    def tick(self):

        self.beat=thalam(root,self.e)

        self.beat.thread.start()

        self.play.configure(text="Stop",command=self.notick)

    def notick(self):

        self.play.configure(text="Start",command=self.tick)

        self.beat.stop()

    def inc(self,a):

    

查看完整描述

2 回答

?
qq_遁去的一_1

由于需要处理器与其他程序共享自身,因此做任何需要时间精度的事情都非常困难。不幸的是,对于定时关键程序,操作系统可以随时选择切换到另一个进程。这可能意味着它可能要等到明显的延迟后才能返回程序。导入时间后使用time.sleep这是一种尝试平衡哔哔声之间时间的更一致的方法,因为处理器的“理由”减少了。尽管Windows上的睡眠默认粒度为15.6ms,但我认为您无需播放超过64Hz的拍子。看来您正在使用多线程来尝试解决您的问题,但是,线程的python实现有时会强制线程按顺序运行。这将使您从流程中退出的情况变得更加糟糕。

我认为最好的解决方案是以所需的频率生成包含节拍器蜂鸣声的声音数据。然后,您可以以操作系统熟悉的方式播放声音数据。由于系统知道如何以可靠的方式处理声音,因此您的节拍器将开始工作。

令人失望的是,但是计时关键的应用程序非常困难,除非您想弄清正在使用的系统。


查看完整回答
反对 回复 2019-12-06
?
qq_花开花谢_0

播放声音来模拟普通的节拍器不需要“实时”功能。


看起来您使用Tkinter框架创建了GUI。root.after()允许您延迟调用函数。您可以使用它来实现刻度:


def tick(interval, function, *args):

    root.after(interval - timer() % interval, tick, interval, function, *args)

    function(*args) # assume it doesn't block

tick()运行function与给定的args每interval毫秒。单个刻度的持续时间受root.after()精度影响,但从长远来看,稳定性仅取决于timer()功能。


这是一个打印一些统计数据(240每分钟心跳数)的脚本:


#!/usr/bin/env python

from __future__ import division, print_function

import sys

from timeit import default_timer

try:

    from Tkinter import Tk

except ImportError: # Python 3

    from tkinter import Tk


def timer():

    return int(default_timer() * 1000 + .5)


def tick(interval, function, *args):

    root.after(interval - timer() % interval, tick, interval, function, *args)

    function(*args) # assume it doesn't block


def bpm(milliseconds):

    """Beats per minute."""

    return 60000 / milliseconds


def print_tempo(last=[timer()], total=[0], count=[0]):

    now = timer()

    elapsed = now - last[0]

    total[0] += elapsed

    count[0] += 1

    average = total[0] / count[0]

    print("{:.1f} BPM, average: {:.0f} BPM, now {}"

          .format(bpm(elapsed), bpm(average), now),

          end='\r', file=sys.stderr)

    last[0] = now


interval = 250 # milliseconds

root = Tk()

root.withdraw() # don't show GUI

root.after(interval - timer() % interval, tick, interval, print_tempo)

root.mainloop()

速度仅拍打一拍:我的机器上为240±1。


查看完整回答
反对 回复 2019-12-06

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信