推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
sudoy
V2EX  ›  Python

Python 做一个闹钟,用 while 循环等待时间是否是一个好办法

  •  
  •   sudoy · Oct 16, 2020 · 13974 views
    This topic created in 2210 days ago, the information mentioned may be changed or developed.

    我在做一个闹钟,等到谋个时间就开始执行谋个动作(在下面的案例里面简化为 print('ok'))。请问这是否是最佳办法?因为我担心会不会导致占用内存过高等问题。我看有一个叫 alarm 的库,也是用 while 循环等待时间。以下是我的示例代码:

    在 2020 年 10 月 17 日 10 点 50 分 50 秒的时候触发事件 print('ok')

    from datetime import datetime
    
    def alarm():
    	while True:
    		now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    		if now == '2020-10-17 10:50:50':
    			print('ok')
    			break
    
    
    if __name__ == '__main__':
    	alarm()
    
    Supplement 1  ·  Oct 17, 2020

    感谢大家的回复!根据大家的建议和帮助,我决定采用计算时间差然后用sleep的办法。其他办法比如用第三方库或者线程等方法也很好,但我希望尽量简单点。这个只需要精确到未来某个时间的秒即可。我更新代码如下,希望对其他新手有帮助:

    from time import sleep
    from datetime import datetime
    
    def alarm():
    	now = datetime.now().timestamp()
    	set_time = datetime(2020, 10, 16, 22, 42, 50).timestamp()
    	delta = set_time - now
    	sleep(delta)
    	print('ok')
    
    
    if __name__ == '__main__':
    	alarm()
    
    
    108 replies  •  2020-10-19 11:38:53 +08:00
    1  2  
    ❮ ❯
    duyuyouci
    duyuyouci
    Oct 16, 2020
    1
    可以用 celery 做定时任务啊
    ruanimal
    ruanimal
    Oct 16, 2020❤️3
    2
    循环里加个 sleep 吧,不然 cpu 都占满了
    nevin47
    nevin47
    Oct 16, 2020
    3
    CPU 都炸了。。。。。。
    RRRoger
    RRRoger
    Oct 16, 2020
    4
    用操作系统的定时任务触发是不是会更好点
    vZexc0m
    vZexc0m
    Oct 16, 2020❤️4
    5
    可以用 APScheduler
    yaoye555
    yaoye555
    Oct 16, 2020❤️1
    6
    crontab 或许更值得拥有
    qile1
    qile1
    Oct 16, 2020 via Android
    7
    这样应该可以,但是有时候 print 有数据,程序确不执行挺奇怪,好像也没有啥好办法
    ysc3839
    ysc3839
    Oct 16, 2020❤️1
    8
    内存占用不高,CPU 使用率会高。如果不想使用操作系统独有的 API 的话,那就加上 sleep 吧。
    no1xsyzy
    no1xsyzy
    Oct 16, 2020
    9
    占满一个核,内存不会泄漏
    不要用等于判断时间
    stephenxiaxy
    stephenxiaxy
    Oct 16, 2020
    10
    。。。
    MoYi123
    MoYi123
    Oct 16, 2020❤️1
    11
    不如 asyncio.sleep
    MagnifierSun
    MagnifierSun
    Oct 16, 2020❤️1
    12
    ??? 你知道这个语句一秒钟要执行多少遍吗哈哈哈
    有个 Schedule 的库,自己去搜搜
    Chenamy2017
    Chenamy2017
    Oct 16, 2020❤️2
    13
    加 sleep 即可,时间也不要用==,超过这个时间后就执行动作。
    Sapp
    Sapp
    Oct 16, 2020
    14
    你这个时间必出坑...
    kimqcn
    kimqcn
    Oct 16, 2020
    15
    谁把我的代码偷出来了呵呵呵
    Vhc001
    Vhc001
    Oct 16, 2020❤️6
    16
    这是我见过最坑爹的代码
    Chaidu
    Chaidu
    Oct 16, 2020❤️1
    17
    建议转行 (狗头
    Tokiomi
    Tokiomi
    Oct 16, 2020
    18
    哈哈哈,学生代码吧
    sudoy
    sudoy
    OP
    Oct 16, 2020
    19
    谢谢大家回复,看来是用 sleep 比较合适。 @duyuyouci celery 可能比较重型了,我想尽量简单点,轻量级的。不过感谢推荐。 @vZexc0m APScheduler 看起来不错,不过还没有用过这个库,回头研究一下
    est
    est
    Oct 16, 2020❤️1
    20
    其实底层库就是你这样实现的。只不过加了很多东西。比如上面说的要加个 sleep(1) 这就是你最小定时精度。
    sudoy
    sudoy
    OP
    Oct 16, 2020
    21
    @Sapp @kimqcn 所以来请教你们啊 :)
    sudoy
    sudoy
    OP
    Oct 16, 2020
    22
    @Chaidu 本来就不是程序猿 哈哈哈,业余爱好者😁🤣
    widewing
    widewing
    Oct 16, 2020 via Android
    23
    sleep 为什么要加在循环里?直接 sleep 指定时间不香吗?
    dswyzx
    dswyzx
    Oct 16, 2020 via iPhone
    24
    别听他们的,加 sleep 万一错过这个点了呢,大于等于时间万一没有拯救世界成功呢。
    综上所述:能用就行!
    imdong
    imdong
    Oct 16, 2020❤️1
    25
    之前有过类似的需求,不过我的做法是用 sleep 但是不是 sleep(1)
    而是再执行完毕后,检查距离下一次执行的时间差,然后睡眠到那个时间。
    momo1999
    momo1999
    Oct 16, 2020
    26
    sleep(0)即可
    est
    est
    Oct 16, 2020
    27
    @widewing 设想一个场景。你在虚拟机里跑起来了这个程序。你让虚拟机暂停了。然后 1 个小时后,恢复了虚拟机。这个时候你的 sleep 还是对的吗。
    sudoy
    sudoy
    OP
    Oct 16, 2020
    28
    @est 哈哈,虽然我找半天没有找到 python 内置的 `sleep()` 是怎么写的,你的话听起来还挺鼓励人的。不过他们说这样写会导致 CUP 占用过高,可能确实没有用 sleep 好,sleep 没有这么高的 CUP 占用。
    wusheng0
    wusheng0
    Oct 16, 2020 via Android
    29
    是不是 fork 一个进程后台运行更好,
    有没有大佬来说一下
    felixcode
    felixcode
    PRO
    Oct 16, 2020
    30
    多开几个闹钟就能把多核 CPU 占满了。
    sudoy
    sudoy
    OP
    Oct 16, 2020
    31
    @shuax sleep(0) 也是解决不了 CUP 占用过高的问题的
    ![]( )
    zkqiang
    zkqiang
    Oct 16, 2020
    32
    没让你 sleep 0 啊。。直接计算 定时减去现在 有多少秒,sleep 多少秒就行了
    ljsh093
    ljsh093
    Oct 16, 2020 via iPhone
    33
    @imdong 设定好 sleep 以后不就没法取消了?只能从外部打断重新设置时间?
    zkqiang
    zkqiang
    Oct 16, 2020❤️1
    34
    或者 sleep(0.5) 每半秒检查一次,另外时间不要用 == 判断,最好用区间判断允许一些误差
    imdong
    imdong
    Oct 16, 2020
    35
    @ljsh093 没有取消的需求,如果有,就在执行前做个判断,一样。

    但是会有类似楼主说的睡眠唤醒的问题。
    bruce00
    bruce00
    Oct 16, 2020
    36
    狗头真的能保命
    heyjei
    heyjei
    Oct 16, 2020
    37
    我真的在生产环境见过这样的代码,你们应该能够理解我当时的心情。
    9LCRwvU14033RHJo
    9LCRwvU14033RHJo
    Oct 16, 2020❤️2
    38
    sleep(0)真实绝了。
    jerfoxu
    jerfoxu
    Oct 16, 2020
    39
    @imdong 这个方法可以哟!
    Norie
    Norie
    Oct 16, 2020 via iPhone
    40
    这是 CPU 性能测试
    fuchunliu
    fuchunliu
    Oct 16, 2020 via Android
    41
    你是对的,他要听他们的,不然别人说你跑的假程序,CPU 都没占用
    ysc3839
    ysc3839
    Oct 16, 2020❤️1
    42
    @est Windows 有 SetThreadpoolTimer,这个可以设置绝对时间,不受睡眠影响,还可以设置允许系统推迟执行,相比 sleep 更加省电。
    winglight2016
    winglight2016
    Oct 16, 2020
    43
    @heyjei 这样的生产环境还能有任何“生产”吗?🐶
    Bijiabo
    Bijiabo
    Oct 16, 2020
    44
    看到 sleep(0) 笑死我了哈哈哈
    lazyfighter
    lazyfighter
    Oct 16, 2020
    45
    既然 sleep,为什么不算一下 sleep 多长时间呢
    ThisQ
    ThisQ
    Oct 16, 2020
    46
    用系统定时任务调用脚本执行呢?
    ysc3839
    ysc3839
    Oct 16, 2020❤️1
    47
    @wusheng0 我一般会选择用新线程来后台执行,fork 在某些操作系统上有坑,比如 Windows 没有 fork,macOS fork 之后不 exec 没法使用 CoreFoundation 。用线程的话可以共享资源,也没有那么多坑。
    zgzb
    zgzb
    Oct 16, 2020 via Android
    48
    我选择 after
    nine9
    nine9
    Oct 16, 2020❤️1
    49
    可以考虑 threading.Event()

    event.wait(timeout=None)
    event.set()

    也就是 APScheduler 这个库实现使用的
    est
    est
    Oct 16, 2020
    50
    @ysc3839 这个就是 OS 帮你做了很多脏活。。。
    0bit
    0bit
    Oct 16, 2020❤️1
    51
    sleep 的问题已经很多人说了,我提一下关于时间比对的问题吧。
    现在这样用 str 比对,容易有小坑,还是应该用更本质的数据去比对,比如 unix timestamp,更不容易出错。
    nuk
    nuk
    Oct 16, 2020
    52
    最好调整成实时优先级,不然这一秒容易被跳过
    findlisa
    findlisa
    Oct 16, 2020 via Android
    53
    @ruanimal 为啥,一个循环就能把 cpu 占满吗
    DoctorCat
    DoctorCat
    Oct 16, 2020❤️1
    54
    兼容 posix 标准的系统还可以利用系统信号:signal 、setitimer 定时器交给 OS 去做了
    ma7x
    ma7x
    Oct 16, 2020
    55
    win10 自带闹钟超级好用 为什么要造轮子
    www5070504
    www5070504
    Oct 16, 2020
    56
    你这种写法 每天多费半度电吧 加个 timer 之类的 sleep 都行啊
    SmartKeyerror
    SmartKeyerror
    Oct 16, 2020
    57
    单线程直接用信号不就好了,向内核注册一个定时器,定时器到期后向进程发送 SIGALRM 信号。
    darknoll
    darknoll
    Oct 16, 2020
    58
    传说中的忙等待自旋锁?
    fish267
    fish267
    Oct 16, 2020
    59
    还是 crontab 吧
    muzuiget
    muzuiget
    Oct 16, 2020
    60
    哈哈,我也想到传说中的自旋锁。
    xionger
    xionger
    Oct 16, 2020
    61
    哈哈 劝改行
    ruanimal
    ruanimal
    Oct 16, 2020
    62
    @findlisa 每时每刻都在判断时间是否相等,也就是 cpu 一直是忙碌的状态,自然就会占满一个核心。如果有 sleep,cpu 在你程序 sleep 的期间就干别的,或者休息去了。

    ps: 去看看操作系统的书,看看进程的调度。
    GoLand
    GoLand
    Oct 16, 2020
    63
    淦,这么精妙的代码我怎么想不到。
    momo1999
    momo1999
    Oct 16, 2020
    64
    哎哟,我错了,sleep 0 确实不行,起码得 0.001
    kiracyan
    kiracyan
    Oct 16, 2020
    65
    硬是要这么做建议你 sleep 个 300 秒 然后判断一下当前时间距离设定时间是不是小于 300 秒 再 sleep 1 秒
    shenqi
    shenqi
    Oct 16, 2020
    66
    。。。明显的实习生写的代码。

    (又不是不能用.jpg )
    Hxu2M811KVSJqN75
    Hxu2M811KVSJqN75
    Oct 16, 2020
    67
    这个算今日最佳 [欢乐贴] 么?
    jimmyismagic
    jimmyismagic
    Oct 16, 2020❤️1
    68
    评论里说实习生写的代码的,自己可以写一个出来试试,看能做到多高的精度,要做到等于而不是大于等于
    caiji11
    caiji11
    Oct 16, 2020
    69
    @xionger 头像可爱 大熊 这个哪里不太好
    sapocaly
    sapocaly
    Oct 16, 2020
    70
    1.https://docs.python.org/3.7/library/sched.html
    2.就是想写代码:用 sleep 或用 os api
    3.用现有 pkg
    iSecret
    iSecret
    Oct 16, 2020
    71
    用 crontab 执行任务的话没这么多蛋疼的事还可以顺道解决了可能需要重复执行的问题,非要用 py 建议 sleep(执行时间 - 当前时间)。
    tabris17
    tabris17
    Oct 16, 2020
    72
    实现了一个野生 spinning
    lane1
    lane1
    Oct 16, 2020
    73
    用术语来说, 你的写法是 spinlock, busy-waiting, CPU-bound... 不过话说计时器到底如何实现呢?
    Tonni
    Tonni
    Oct 16, 2020❤️1
    74
    哈哈,别的不说,楼主头像的狗子好可爱🐶
    UN2758
    UN2758
    Oct 16, 2020❤️1
    75
    lz 这么狂野的写法,怀念当年的我,哈哈哈哈
    JCZ2MkKb5S8ZX9pq
    JCZ2MkKb5S8ZX9pq
    Oct 16, 2020
    76
    直接算 timestamp 的时间差,sleep 一次到底不就好了。
    这个格式化时间的操作有点多余,重复计算没必要啊。
    wuwukai007
    wuwukai007
    Oct 16, 2020 via Android
    77
    直接计算时间差,sleep,每次激活的时候重新计算,
    lysS
    lysS
    Oct 16, 2020
    78
    想到见过 JS 延时函数:
            function sleepSync(ms) {
                var curr = new Date().getTime();
                ms += curr;
                while (curr < ms) {
                    curr = new Date().getTime();
                }
            }
    CSM
    CSM
    Oct 16, 2020 via Android
    79
    直接一觉睡到目标时间,醒来后完成任务就行,循环也不用
    echoick
    echoick
    Oct 16, 2020 via iPhone
    80
    哈哈哈哈 sleep(0)
    inframe
    inframe
    Oct 16, 2020
    81
    我真的在生产环境见过这样的代码,你们应该能够理解我当时的心情。

    +1
    ctro15547
    ctro15547
    Oct 16, 2020
    82
    延迟 0.1 秒就行 。。
    E1n
    E1n
    Oct 16, 2020 via Android
    83
    哈哈加油
    Yinz
    Yinz
    Oct 17, 2020
    84
    不得不说,楼主心态蛮好的,加油,谁都有新手阶段,学习即可
    by73
    by73
    Oct 17, 2020
    85
    突然对 time.sleep 有了点兴趣,最后发现居然调用的是 select() 系统调用😂
    irytu
    irytu
    Oct 17, 2020
    86
    os.sched_yield()

    不过 Windows 上没有这种方法 我一般为了 portable 会写成 time.sleep(0.0001)
    vcfghtyjc
    vcfghtyjc
    Oct 17, 2020❤️1
    87
    运行时候检测一下当前时间,然后算出需要的睡眠时间,sleep 就行了
    shijingshijing
    shijingshijing
    Oct 17, 2020
    88
    sleep(0)没毛病,代码不改,在 crontab 里面设定 2020 年 10 月 17 日 10 点 50 分 50 秒执行一次就 ok 了。
    discrete
    discrete
    Oct 17, 2020
    89
    想起了 Sleep Sort.
    sudoy
    sudoy
    OP
    Oct 17, 2020
    90
    @nuk 谢谢!请问具体怎么操作?
    sudoy
    sudoy
    OP
    Oct 17, 2020
    91
    @ma7x 这个问题问的好。当然是定时调用 API 啦,Windows 10 自带的闹钟并非可编程的
    inorilzy
    inorilzy
    Oct 17, 2020
    92
    APScheduler 和 celery 都可以定时任务。
    findlisa
    findlisa
    Oct 17, 2020 via Android
    93
    @ruanimal 好的👌
    raymanr
    raymanr
    Oct 17, 2020
    94
    @sudoy 如果纯粹是为了定时的话, 就 windows 的任务计划就挺好, 而且足够可靠, 自己写会有很多坑
    sudoy
    sudoy
    OP
    Oct 17, 2020 via iPhone
    95
    @raymanr 谢谢
    flgn88
    flgn88
    Oct 17, 2020 via iPhone
    96
    为何我想起了大名鼎鼎的“睡眠排序法”?!
    sudoy
    sudoy
    OP
    Oct 17, 2020 via iPhone
    97
    @nuistzhou 就是那个从天而降的掌法吗?
    adamwong
    adamwong
    Oct 17, 2020
    98
    @SmartKeyerror 我怎么又抓到你了
    nuk
    nuk
    Oct 17, 2020❤️1
    99
    @sudoy
    import win32api,win32process,win32con

    pid = win32api.GetCurrentProcessId()
    handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
    win32process.SetPriorityClass(handle, win32process.REALTIME_PRIORITY_CLASS)
    IDAEngine
    IDAEngine
    Oct 17, 2020 via iPhone
    100
    用系统 API 不香吗? while sleep 不靠谱
    1  2  
    ❮ ❯
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5481 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 341ms · UTC 02:02 · PVG 10:02 · LAX 18:02 · JFK 21:02
    ♥ Do have faith in what you're doing.