您可以使用time 模块来执行此操作:
import time
def call_at_time(fun, t):
sleep_time = t - time.time()
assert sleep_time > 0 # make sure t is in the future
time.sleep(sleep_time)
fun()
使用这个函数看起来像这样:
t = time.strptime("2021-02-22 23:50:30", "%Y-%m-%d %H:%M:%S")
t = time.mktime(t)
print(f"scheduled at {t}")
call_at_time(lambda: print(f"hello at {time.time()}"), t)
那么这有多准确?这是一个小实验来找出答案。如果您想要更可靠的结果,请使用更大的n。
n = 20
results = []
for _ in range(n):
t = time.time() + 2 # 2 seconds in the future
call_at_time(lambda: results.append(abs(time.time() - t)), t)
print(f"min={min(results):5.4f}, max={max(results):5.4f}, mean={sum(results) / n:5.4f}")
在我的 Windows 机器上,这给了我:
min=0.0010, max=0.0200, mean=0.0094
因此,我们平均减少了大约 9 毫秒,但有时我们减少了多达 20 毫秒。这种不准确来自两个来源
-
time.sleep 并没有给你完美的保证(它可能会睡得更短或更长)
- time.time() 不一定具有很高的准确性,具体取决于您的系统。例如,请参阅讨论 here。
为了说明 time.time() 的(不)准确性,您可以在循环中运行它并打印结果数字。
while True:
print(time.time())
在我的 Windows 机器上,这给了我这样的东西:
...
1614072496.454525
1614072496.454525
1614072496.454525
1614072496.4555244
1614072496.4555244
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4605293
1614072496.4605293
1614072496.4605293
...
如您所见,time.time() 可能非常不稳定,这当然会限制您完成所需任务的准确度(以及我上面的实验结果实际上有多准确......)。
如果您使用的系统 time.time() 可以为您提供更好的准确性,或者您找到了另一种获得更好系统时间的方法,则可以通过将睡眠与一些忙碌的等待结合起来获得更好的结果。这样你至少可以消除你从 time.sleep() 得到的不准确性。
def call_at_time_high_precision(fun, t, busy_waiting_time=1):
sleep_time = t - time.time()
assert sleep_time > 0 # make sure time is in the future
if sleep_time > busy_waiting_time:
time.sleep(sleep_time - busy_waiting_time)
while t > time.time(): # busy wait until the event
pass
fun()