RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1550116
Accepted
Dark Space
Dark Space
Asked:2023-11-07 19:18:38 +0000 UTC2023-11-07 19:18:38 +0000 UTC 2023-11-07 19:18:38 +0000 UTC

异步运行函数

  • 772

大家好。为了这个想法,我想编写某种控制台秒表。吃

import os
import asyncio
import time
import logging


logging.basicConfig(filename = "mylog.log", level=logging.DEBUG)


class Timer(): 
    def __init__(self) -> None:
        self.minute = 0
        self.seconds = 0
        self.deciseconds = 0


    def add_deciseconds(self): 
        self.deciseconds += 1

        if self.deciseconds >= 10: 
            self.seconds += 1 
            self.deciseconds = 0 

        if self.seconds >= 60: 
            self.seconds = 0 
            self.minute += 1


    def get_time(self):
        return (self.minute, self.seconds, self.deciseconds) 


async def tick(my_timer: Timer):
    my_timer.add_deciseconds()
    os.system("cls") 
    m , s, ss = my_timer.get_time()
    print(f"{m} : {s} : {ss}")

    
async def main(tim): 
    await tick(tim)


if __name__ == '__main__': 

    my_timer = Timer()
    
    while True: 

        start = time.time()
        logging.debug(start)

        asyncio.run(main(my_timer))   

        time.sleep(1)

        end = time.time()
        logging.debug(end)
        logging.debug(end - start)
        logging.debug('------------------')

    

日志和异步已经是解决问题的尝试。
问题:time.sleep(1)等待超过 1 秒。为了进行测试,我打开了这个应用程序,几秒钟后打开了手机上的秒表。大约第二分钟,手机上的秒表开始追上。

我对异步编程不太了解,但我认为输出到时间终端并加一的代码使程序仍然等待,所以我尝试使函数异步。受到文档中模板的启发

日志看起来像这样:

DEBUG:root:1699353460.6091332
DEBUG:asyncio:Using proactor: IocpProactor
DEBUG:root:1699353461.6302617
DEBUG:root:1.0211284160614014 # Разница между старт и стоп больше 1 секунды
DEBUG:root:------------------
DEBUG:root:1699353461.6313007
DEBUG:asyncio:Using proactor: IocpProactor
DEBUG:root:1699353462.666385
DEBUG:root:1.0350842475891113 # Разница между старт и стоп больше 1 секунды
DEBUG:root:------------------
    

我读过各种文章,包括其他人对 SO 的问题(一个例子)。他们说该误差是可以接受的,但他们谈论的误差约为 0.00001 或更小。

我尝试在没有任何计时器的情况下运行循环:

while True: 

    start = time.time()
    logging.debug(start)

    time.sleep(1)

    end = time.time()
    logging.debug(end)
    logging.debug(end - start)
    logging.debug('------------------') 

在这种情况下,日志中的数字已经更加准确

DEBUG:root:1699355102.4560356
DEBUG:root:1699355103.4560683
DEBUG:root:1.000032663345337
DEBUG:root:------------------
DEBUG:root:1699355103.457032
DEBUG:root:1699355104.4571276
DEBUG:root:1.0000956058502197
DEBUG:root:------------------

如果不进行日志记录,计时器的运行速度仍然会慢一些。
我不知道到底是什么减慢了我的程序?

python
  • 2 2 个回答
  • 57 Views

2 个回答

  • Voted
  1. Best Answer
    eri
    2023-11-07T19:40:56Z2023-11-07T19:40:56Z

    os.system("cls") 第一种情况和logging.debug第二种情况下的调用会减慢您的程序的速度。

    • 3
  2. insolor
    2023-11-08T14:04:26Z2023-11-08T14:04:26Z

    time.sleep()给你的代码增加了延迟,但是你的代码本身并没有在零时间内运行,导致计时器逐渐落后于实时。

    即使是简单的计时sleep

    import time
    
    t = time.time()
    time.sleep(1.0)
    dt = time.time() - t
    print(dt)
    

    将显示实际延迟超过 1 秒(它为我显示1.000610113143921)。随着样本之间的代码增多(以及速度较慢的代码,例如 I/O,包括 cls),额外的延迟会更大,并且循环中的滞后会逐渐增加。

    另外,操作系统不保证延迟的绝对准确性;某些进程可能会长时间占用内核,可能不会在计划的时间从“睡眠”返回。

    假设没有繁重的后台进程,您可以考虑迭代的实际执行时间来重新计算延迟。好吧,显示的是实际经过的时间(根据电脑计时器),而不是手动计算的。具有延迟重新计算功能的计时器原型,每秒应执行 10 次迭代:

    import time
    
    target_dt = 0.1  # Целевой промежуток времени между итерациями (десять итераций в секунду)
    dt = target_dt  # Целевое значение задержки между итерациями берем как начальное
    
    t = time.time()
    prev_time = t
    
    while True:
        print(f"{prev_time - t:.3f}, {dt}")
    
        time.sleep(dt)
        # time.sleep(0.01)  # Даже если специально добавить дополнительную задержку, dt пересчитается так, чтобы ее учитывать
    
        current_time = time.time()
        # Фактический промежуток времени между итерациями
        dt_fact = current_time - prev_time
    
        # Пересчитываем задержку с поправкой на разницу между фактической задержкой и требуемой
        dt = target_dt - (dt_fact  - dt)
        prev_time = current_time
    

    结论:

    0.000, 0.1
    0.100, 0.09979171752929689
    0.200, 0.09970550537109377
    0.300, 0.099810266494751
    0.400, 0.09973764419555667
    0.500, 0.0997503757476807
    0.600, 0.09978647232055668
    0.700, 0.09971432685852055
    0.800, 0.09980025291442876
    0.900, 0.09976506233215338
    1.000, 0.09972820281982428
    1.100, 0.09979052543640143
    1.200, 0.09976487159729011
    1.300, 0.09973921775817879
    1.400, 0.09974193572998055
    1.500, 0.0997568130493165
    1.600, 0.09974713325500498
    1.700, 0.09976415634155283
    1.800, 0.09980382919311534
    1.900, 0.09972858428955089
    2.000, 0.09971747398376477
    2.100, 0.09978790283203137
    2.200, 0.09974532127380384
    2.300, 0.09975781440734877
    2.400, 0.09979414939880385
    2.500, 0.09974107742309585
    2.600, 0.09973020553588882
    2.700, 0.09979276657104508
    2.800, 0.09974160194396989
    2.900, 0.09979963302612321
    3.000, 0.09978470802307146
    3.100, 0.09977574348449725
    3.200, 0.09972982406616229
    3.300, 0.0997399330139162
    3.400, 0.09973549842834492
    3.500, 0.09977755546569844
    3.600, 0.09981722831726095
    3.700, 0.09977011680603048
    3.800, 0.09973802566528342
    3.900, 0.09972071647644065
    4.000, 0.09967408180236839
    ...
    

    可以看出,迭代之间保持了大约+-0.001的精度差距。

    在 Linux 上测试;在 Windows 上结果可能不同(似乎在那里你不能以优于 0.01 秒的精度进行延迟,因为这样计时器的精度可能会更差)。

    我认为将计时器放在异步函数中没有多大意义。如果在同一事件循环中执行其他函数,这将增加额外的随机误差。如有必要,请在单独的线程中运行它。

    • 1

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5