Python 中的延迟函数

2025-03-04 08:25:00
admin
原创
76
摘要:问题描述:在 JavaScript 中,我习惯于调用稍后执行的函数,如下所示function foo() { alert('bar'); } setTimeout(foo, 1000); 这不会阻止其他代码的执行。我不知道如何在 Python 中实现类似的东西。我可以使用 sleepimport t...

问题描述:

在 JavaScript 中,我习惯于调用稍后执行的函数,如下所示

function foo() {
    alert('bar');
}

setTimeout(foo, 1000);

这不会阻止其他代码的执行。

我不知道如何在 Python 中实现类似的东西。我可以使用 sleep

import time
def foo():
    print('bar')

time.sleep(1)
foo()

但这会阻止其他代码的执行。(实际上,就我而言,阻止 Python 本身不是问题,但我无法对该方法进行单元测试。)

我知道线程是为不同步执行而设计的,但我想知道是否存在更简单、类似setTimeoutsetInterval类似的方法。


解决方案 1:

要在延迟后执行某个功能或者使用事件循环(无线程)在给定的秒数内重复某个功能,您可以:

特金特

#!/usr/bin/env python
from Tkinter import Tk

def foo():
    print("timer went off!")

def countdown(n, bps, root):
    if n == 0:
        root.destroy() # exit mainloop
    else:
        print(n)
        root.after(1000 / bps, countdown, n - 1, bps, root)  # repeat the call

root = Tk()
root.withdraw() # don't show the GUI window
root.after(4000, foo) # call foo() in 4 seconds
root.after(0, countdown, 10, 2, root)  # show that we are alive
root.mainloop()
print("done")

输出

10
9
8
7
6
5
4
3
timer went off!
2
1
done

鍵盤

#!/usr/bin/env python
from gi.repository import GObject, Gtk

def foo():
    print("timer went off!")

def countdown(n): # note: a closure could have been used here instead
    if n[0] == 0:
        Gtk.main_quit() # exit mainloop
    else:
        print(n[0])
        n[0] -= 1
        return True # repeat the call

GObject.timeout_add(4000, foo) # call foo() in 4 seconds
GObject.timeout_add(500, countdown, [10])
Gtk.main()
print("done")

输出

10
9
8
7
6
5
4
timer went off!
3
2
1
done

扭曲

#!/usr/bin/env python
from twisted.internet import reactor
from twisted.internet.task import LoopingCall

def foo():
    print("timer went off!")

def countdown(n):
    if n[0] == 0:
        reactor.stop() # exit mainloop
    else:
        print(n[0])
        n[0] -= 1

reactor.callLater(4, foo) # call foo() in 4 seconds
LoopingCall(countdown, [10]).start(.5)  # repeat the call in .5 seconds
reactor.run()
print("done")

输出

10
9
8
7
6
5
4
3
timer went off!
2
1
done

异步

Python 3.4为异步 IO引入了新的临时 API--asyncio模块:

#!/usr/bin/env python3.4
import asyncio

def foo():
    print("timer went off!")

def countdown(n):
    if n[0] == 0:
        loop.stop() # end loop.run_forever()
    else:
        print(n[0])
        n[0] -= 1

def frange(start=0, stop=None, step=1):
    while stop is None or start < stop:
        yield start
        start += step #NOTE: loss of precision over time

def call_every(loop, seconds, func, *args, now=True):
    def repeat(now=True, times=frange(loop.time() + seconds, None, seconds)):
        if now:
            func(*args)
        loop.call_at(next(times), repeat)
    repeat(now=now)

loop = asyncio.get_event_loop()
loop.call_later(4, foo) # call foo() in 4 seconds
call_every(loop, 0.5, countdown, [10]) # repeat the call every .5 seconds
loop.run_forever()
loop.close()
print("done")

输出

10
9
8
7
6
5
4
3
timer went off!
2
1
done

注意:这些方法的界面和行为略有不同。

解决方案 2:

您需要一个Timer来自模块的对象threading

from threading import Timer
from time import sleep

def foo():
    print "timer went off!"
t = Timer(4, foo)
t.start()
for i in range(11):
    print i
    sleep(.5)

如果您想重复,这里有一个简单的解决方案:不要使用Timer,只需使用Thread但传递一个类似于这样的函数:

def call_delay(delay, repetitions, func, *args, **kwargs):             
    for i in range(repetitions):    
        sleep(delay)
        func(*args, *kwargs)

这不会产生无限循环,因为如果操作不当,这可能会导致线程不会终止,并产生其他令人不快的行为。更复杂的方法可能是使用Event基于的方法,比如这个。

解决方案 3:

像 Javascript 这样的异步回调setTimeout需要事件驱动的架构。

流行的twisted等 Python 异步框架可以满足CallLater您的需求,但这意味着在您的应用程序中采用事件驱动的架构。

另一种选择是使用线程并在线程中休眠。Python 提供了一个计时器来简化等待部分。但是,当您的线程唤醒并执行您的函数时,它将处于单独的线程中,并且必须以线程安全的方式执行它所做的一切。

解决方案 4:

抱歉,我不能发布超过 2 个链接,因此有关更多信息,请查看PEP 380以及最重要的asyncio文档

除非您坚持使用线程或多处理,否则 asyncio 是解决此类问题的首选方案。它由 GvR 设计和实施,名称为“Tulip”。GvR 在PyCon 2013上推出了它,旨在成为一个事件循环来统治(和标准化)所有事件循环(如 twisted、gevent 等中的事件循环),并使它们彼此兼容。之前已经提到过 asyncio,但 asyncio 的真正威力是通过Yield from释放出来的。

# asyncio is in standard lib for latest python releases (since 3.3)
import asyncio

# there's only one event loop, let's fetch that
loop = asyncio.get_event_loop()

# this is a simple reminder that we're dealing with a coro
@asyncio.coroutine
def f():
    for x in range(10):
        print(x)
        # we return with a coroutine-object from the function, 
        # saving the state of the execution to return to this point later
        # in this case it's a special sleep
        yield from asyncio.sleep(3)

# one of a few ways to insert one-off function calls into the event loop
loop.call_later(10, print, "ding!")
# we insert the above function to run until the coro-object from f is exhausted and 
# raises a StopIteration (which happens when the function would return normally)
# this also stops the loop and cleans up - keep in mind, it's not DEAD but can be restarted
loop.run_until_complete(f())
# this closes the loop - now it's DEAD
loop.close()

================

>>> 
0
1
2
3
ding!
4
5
6
7
8
9
>>>

解决方案 5:

JavaScript 可以做到这一点,因为它在事件循环中运行。在 Python 中,这可以通过使用 Twisted 等事件循环或通过 GLib 或 Qt 等工具包来实现。

解决方案 6:

问题是您的普通 Python 脚本不在框架中运行。脚本被调用并控制主循环。使用 JavaScript,您页面上运行的所有脚本都在框架中运行,并且当超时时,框架会调用您的方法。

我自己没有使用过 pyQt(只使用过 C++ Qt),但您可以使用 startTimer() 在任何 QObject 上设置计时器。计时器到时,将调用您的方法上的回调。您还可以使用 QTimer 并将超时信号连接到任意插槽。这是可能的,因为 Qt 运行一个事件循环,可以在稍后阶段调用您的方法。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2757  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1693  
  在全球化的浪潮下,企业的业务范围不断拓展,跨文化协作变得愈发普遍。不同文化背景的团队成员在合作过程中,由于语言、价值观、工作习惯等方面的差异,往往会面临诸多沟通挑战。而产品生命周期管理(PLM)系统作为企业管理产品全生命周期的重要工具,如何有效支持跨文化协作成为了关键问题。通过合理运用沟通策略,PLM系统能够在跨文化团...
plm是什么软件   15  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色,其中文档版本控制是确保产品数据准确性、完整性和可追溯性的关键环节。有效的文档版本控制能够避免因版本混乱导致的错误、重复工作以及沟通不畅等问题,提升企业整体的运营效率和产品质量。接下来,我们将深入探讨 PLM 系统实现文档版本控制的 6...
plm是什么意思   19  
  PLM(产品生命周期管理)项目管理旨在通过有效整合流程、数据和人员,优化产品从概念到退役的整个生命周期。在这个过程中,敏捷测试成为确保产品质量、加速交付的关键环节。敏捷测试强调快速反馈、持续改进以及与开发的紧密协作,对传统的测试流程提出了新的挑战与机遇。通过对测试流程的优化,能够更好地适应PLM项目的动态变化,提升产品...
plm管理系统   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用