Python 周期性地几乎正确地触发函数的一种方法

Python 周期性地几乎正确地触发函数的一种方法,python,time,scheduled-tasks,milliseconds,Python,Time,Scheduled Tasks,Milliseconds,我想周期性地触发一个函数,比如说,每个5s。该函数不会占用很多CPU时间,因此我希望即使它是一个阻塞函数,也不会成为问题。我知道python永远不会是一种实时语言,即使它运行在实时操作系统上,我只是想避免延迟,以显著增加和取消数据采集的同步 我比较了两种不同的解决方法,我有点惊讶。使用线程模块(在SO上找到的解决方案),会有一个加起来的延迟,即使在100秒的短时间内,这也很重要 import time import threading # Function to trigger def q(t

我想周期性地触发一个函数,比如说,每个5s。该函数不会占用很多CPU时间,因此我希望即使它是一个阻塞函数,也不会成为问题。我知道python永远不会是一种实时语言,即使它运行在实时操作系统上,我只是想避免延迟,以显著增加和取消数据采集的同步

我比较了两种不同的解决方法,我有点惊讶。使用
线程
模块(在SO上找到的解决方案),会有一个加起来的延迟,即使在100秒的短时间内,这也很重要

import time
import threading

# Function to trigger
def q(t0, t1):
    print("{}: {}".format(t1, t1-t0))

# Scheduler:
def f(t):
    t0 = time.clock()
    q(t, t0)
    threading.Timer(5, f, (t0, )).start()

f(time.clock())
输出为:

1.2439980979269082e-06: 6.219990489634541e-07
5.003068943307586: 5.003067699309487
10.009677372203297: 5.006608428895712
15.017115547830327: 5.00743817562703
20.02463987032564: 5.007524322495312
25.03211007890369: 5.007470208578049
30.039602057448455: 5.007491978544767
35.04705640505075: 5.007454347602298
40.0545011116678: 5.0074447066170436
45.06215045597195: 5.007649344304156
50.069445571817724: 5.007295115845771
55.076933507368665: 5.007487935550941
60.0844149119296: 5.007481404560934
65.09188791950338: 5.007473007573779
70.09936870206525: 5.007480782561871
75.10685632661668: 5.00748762455143
80.11432187020186: 5.007465543585184
85.12207042335432: 5.007748553152453
90.12924456038506: 5.007174137030745
95.13673964892507: 5.007495088540011
100.1442070585074: 5.007467409582333
105.15168068808023: 5.007473629572829
当我使用微控制器的老式C风格代码解决问题时:

import time

# Function to trigger:
def q(t0, t1):
    print("{}: {}".format(t1, t1-t0))

# Scheduler:
t0 = time.clock()
while True:
    t1 = time.clock()
    if (t1-t0)>=5:
        q(t0, t1)
        t0 = t1
我得到:

5.0000009329985735: 5.0
10.000001243998097: 5.000000310999524
15.000001243998097: 5.0
20.0000012439981: 5.000000000000002
25.0000012439981: 5.0
30.0000012439981: 5.0
35.0000012439981: 5.0
40.0000012439981: 5.0
45.0000012439981: 5.0
50.0000012439981: 5.0
55.0000012439981: 5.0
60.0000012439981: 5.0
65.0000012439981: 5.0
70.0000012439981: 5.0
75.0000012439981: 5.0
80.0000012439981: 5.0
85.0000012439981: 5.0
90.0000012439981: 5.0
95.0000012439981: 5.0
100.0000012439981: 5.0
105.0000012439981: 5.0
这似乎更可靠。我知道这些显示中可能存在浮点问题,但无法解释这两种解决方案之间的差异

  • 是因为
    线程
    模块依赖于
    时间。睡眠
    功能吗
在我看来,我会说,第二种选择更好,因为它避免了线程和递归,即使它使用了无止境的循环。 -有没有更好的方法来实现这一目标

深入我的问题:
-如何在定义的时间戳上同步触发器?
sched
模块是否有用?

问题中描述的第二种方法会产生一个繁忙的循环(消耗所有CPU)

另一种比使用线程更简单的方法是使用良好的旧
select
系统调用:

import time
import select
import socket # win

s = socket.socket() # win

# Function to trigger:
def q(t0, t1):
    print("{}: {}".format(t1, t1-t0))

# Scheduler:
t0 = time.time()
while True:
    select.select([s],[],[],5) #wait for 5 seconds (dummy socket for win)
    t1 = time.time()
    q(t0, t1)
    t0 = t1
结果:

1441792007.3: 5.00524997711
1441792012.3: 5.00554990768
1441792017.31: 5.00520896912
1441792022.31: 5.00508904457
1441792027.32: 5.00518012047
1441792032.32: 5.00523996353
1441792037.33: 5.00523781776
而且,
time.clock
在Linux上对我不起作用。文件说:

在Unix上,方法clock()以浮点数形式返回当前处理器时间,以秒为单位。精度取决于同名C函数的精度,但在任何情况下,这都是用于基准测试Python或计时算法的函数

在Windows上,此函数基于Win32函数QueryPerformanceCounter,以浮点数形式返回自第一次调用此函数以来经过的挂钟秒数

也许你在Windows上?或者你在Linux上,但第二个例子是 使CPU繁忙,
时间。时钟确实给出了一个数字,而对于我的代码,它总是0,因为没有真正涉及CPU周期。

是的,我在windows上开发(但我尝试在Linux上兼容),这不是我自己的选择,这是一个限制。不幸的是,windows上的“select”仅适用于套接字。我必须导入一个“socket”,创建一个虚拟的socket来为select提供信息,如果没有,就会引发错误(谢谢windows)。