如何制作时间延迟?

3201

我如何在Python脚本中添加时间延迟?


14
可能是 如何让我的Python程序休眠50毫秒? 的重复问题。 - Peter Mortensen
1
投票重新开放,因为这似乎比链接的重复问题更好作为规范。 - user16217248
13个回答

3446
这会延迟2.5秒:
import time

time.sleep(2.5)

这是另一个例子,其中某事大约每分钟运行一次。
import time

while True:
    print("This prints once a minute.")
    time.sleep(60) # Delay for 1 minute (60 seconds).

43
如果您需要一些条件才能发生,最好使用threading.Event.wait - ssj
23
嗯...它不会那么频繁地打印,因为打印和处理所有相关的缓冲区需要时间(可能会进行内核上下文切换),还需要注册闹钟信号,但是...大约不到一分钟一次。 - Parthian Shot
24
使用tkinter作为图形用户界面时,sleep()函数不能起到作用 - 需要使用after()函数代替:tkinter.Tk.after(yourrootwindow,60000) 或 _yourrootwindow.after(60000)_。 - DonGru
9
值得一提的是,在Windows中,你最好能获得约0.015秒(15毫秒)的精度。而在现代处理器上,大多数Linux版本可以达到0.001秒(1毫秒)的精度。 - SDsolar
3
确实。Tkinter的评论最好以答案的形式呈现,而不是以评论的形式。我们在这里构建一个将长期存在的数据库,人们通过Google寻找答案,许多人从未阅读评论。这将成为一个很好的新问题。可以提出类似于“如何在使用tkinter时制作时间延迟”的问题或类似问题。 - SDsolar
显示剩余3条评论

869

使用time模块中的sleep()函数。它可以接受一个浮点数作为亚秒分辨率的参数。

from time import sleep
sleep(0.1)  # Time in seconds

3
时间分辨率怎么样?例如,它是否存在16.66毫秒的倍数风险(尽管在示例中恰好为0.1秒,即6个16.66毫秒的倍数)?或者至少保证1毫秒?例如,指定3毫秒的延迟是否实际上可能导致17毫秒的延迟? - Peter Mortensen
也许打印一些精度(冗长)会很好?作为未来的*事情可能。 - William Martens

112

如何在Python中实现时间延迟?

在单线程中,我建议使用sleep函数

>>> from time import sleep

>>> sleep(4)

这个函数实际上是由操作系统挂起调用它的线程的处理,让其他线程和进程在其休眠时执行。

可以用它来达到这个目的,或者仅仅是为了延迟一个函数的执行。例如:

>>> def party_time():
...     print('hooray!')
...
>>> sleep(3); party_time()
hooray!

在我按下Enter键后,3秒钟后会打印出"hooray!"。

使用多个线程和进程的示例

同样地,sleep可以暂停您的线程,并几乎不消耗任何处理能力。

为了演示,创建一个如下的脚本(我最初尝试在交互式Python 3.5 shell中执行此操作,但由于某种原因,子进程无法找到party_later函数):

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed
from time import sleep, time

def party_later(kind='', n=''):
    sleep(3)
    return kind + n + ' party time!: ' + __name__

def main():
    with ProcessPoolExecutor() as proc_executor:
        with ThreadPoolExecutor() as thread_executor:
            start_time = time()
            proc_future1 = proc_executor.submit(party_later, kind='proc', n='1')
            proc_future2 = proc_executor.submit(party_later, kind='proc', n='2')
            thread_future1 = thread_executor.submit(party_later, kind='thread', n='1')
            thread_future2 = thread_executor.submit(party_later, kind='thread', n='2')
            for f in as_completed([
              proc_future1, proc_future2, thread_future1, thread_future2,]):
                print(f.result())
            end_time = time()
    print('total time to execute four 3-sec functions:', end_time - start_time)

if __name__ == '__main__':
    main()

这个脚本的示例输出如下:
thread1 party time!: __main__
thread2 party time!: __main__
proc1 party time!: __mp_main__
proc2 party time!: __mp_main__
total time to execute four 3-sec functions: 3.4519670009613037

多线程

使用 Timer threading 对象,可以在单独的线程中触发一个函数在稍后被调用:

>>> from threading import Timer
>>> t = Timer(3, party_time, args=None, kwargs=None)
>>> t.start()
>>>
>>> hooray!

>>>

空白行说明函数已经输出到我的标准输出,我必须按Enter键以确保我在提示符上。
这种方法的好处是,当Timer线程等待时,我可以做其他事情,在这种情况下,先按一次Enter键,然后再执行该函数(请参见第一个空白提示符)。
multiprocessing库中没有相应的对象。您可以创建一个,但可能没有理由。对于简单的计时器,子线程比全新的子进程更有意义。

84

延迟还可以通过以下方法实现。

第一种方法:

import time
time.sleep(5) # Delay for 5 seconds.
第二种延迟的方法是使用隐式等待方法:
 driver.implicitly_wait(5)
第三种方法在需要等待特定操作完成或找到元素时更加有用:
self.wait.until(EC.presence_of_element_located((By.ID, 'UserName'))

21
第二和第三种方法并非纯粹的Python代码,而是与Selenium相关的。在进行端到端测试时会用到它们。OP没有提到其中任何一种方法。 - alexandernst

73
我知道五种方法: time.sleep(), pygame.time.wait(), matplotlib的pyplot.pause(), .after()asyncio.sleep()
time.sleep()示例(如果使用tkinter,请勿使用):
import time
print('Hello')
time.sleep(5) # Number of seconds
print('Bye')

pygame.time.wait()示例(如果您没有使用pygame窗口,则不建议使用,但是您可以立即退出窗口):

import pygame
# If you are going to use the time module
# don't do "from pygame import *"
pygame.init()
print('Hello')
pygame.time.wait(5000) # Milliseconds
print('Bye')

matplotlib的函数pyplot.pause()示例(如果您没有使用图形,则不建议使用,但是您可以立即退出图形):

import matplotlib
print('Hello')
matplotlib.pyplot.pause(5) # Seconds
print('Bye')

.after() 方法(最好与 Tkinter 一起使用):

import tkinter as tk # Tkinter for Python 2
root = tk.Tk()
print('Hello')
def ohhi():
    print('Oh, hi!')
root.after(5000, ohhi) # Milliseconds and then a function
print('Bye')

最后,asyncio.sleep() 方法(必须在异步循环中):

await asyncio.sleep(5)

driver.implicitly_wait() 是 Selenium WebDriver 的一个方法,它设置了在网页上查找元素的默认等待时间。这与所提出的问题完全无关。 - Corey Goldberg
这不是 asyncio.sleep 的工作方式。必须在事件循环内部使用 await。它不是通用延迟。 - MisterMiyagi

55

一个有趣的与睡眠生成器相关的小技巧。

问题涉及时间延迟。它可以是固定时间,但在某些情况下,我们可能需要自上次以来度量的延迟时间。以下是一种可能的解决方案:

自上次唤醒以来度量的延迟时间(定期唤醒)

情况可能是这样的:我们希望尽可能定期地执行某些操作,并且不想在代码周围处理所有last_timenext_time等等的事情。

蜂鸣器生成器

以下代码 (sleepy.py) 定义了一个 buzzergen 生成器:

import time
from itertools import count

def buzzergen(period):
    nexttime = time.time() + period
    for i in count():
        now = time.time()
        tosleep = nexttime - now
        if tosleep > 0:
            time.sleep(tosleep)
            nexttime += period
        else:
            nexttime = now + period
        yield i, nexttime

调用常规蜂鸣器生成器

from sleepy import buzzergen
import time
buzzer = buzzergen(3) # Planning to wake up each 3 seconds
print time.time()
buzzer.next()
print time.time()
time.sleep(2)
buzzer.next()
print time.time()
time.sleep(5) # Sleeping a bit longer than usually
buzzer.next()
print time.time()
buzzer.next()
print time.time()

运行它,我们看到:

1400102636.46
1400102639.46
1400102642.46
1400102647.47
1400102650.47

我们也可以直接在循环中使用它:

import random
for ring in buzzergen(3):
    print "now", time.time()
    print "ring", ring
    time.sleep(random.choice([0, 2, 4, 6]))

运行它,我们可能会看到:

now 1400102751.46
ring (0, 1400102754.461676)
now 1400102754.46
ring (1, 1400102757.461676)
now 1400102757.46
ring (2, 1400102760.461676)
now 1400102760.46
ring (3, 1400102763.461676)
now 1400102766.47
ring (4, 1400102769.47115)
now 1400102769.47
ring (5, 1400102772.47115)
now 1400102772.47
ring (6, 1400102775.47115)
now 1400102775.47
ring (7, 1400102778.47115)

正如我们所看到的,这个蜂鸣器并不太严格,即使我们睡过头或打乱了日常作息时间,也可以帮助我们赶上规律的瞌睡间隔。


35
Python标准库中的Tkinter库是一个交互式工具,您可以导入它。基本上,您可以创建按钮、框和弹出窗口等内容,并将它们作为窗口显示,通过代码进行操作。
如果您使用Tkinter,请不要使用time.sleep(),因为它会破坏您的程序。我曾经遇到过这种情况。相反,使用root.after(),并用毫秒替换多少秒的值。例如,time.sleep(1)在Tkinter中等同于root.after(1000)
否则,time.sleep(),正如许多答案所指出的那样,是可行的方法。

27
Delays是使用时间库完成的,具体来说是time.sleep()函数。
只需等待一秒钟:
from time import sleep
sleep(1)

这能够工作的原因是通过执行:
from time import sleep

你需要从time库中仅提取睡眠函数,这意味着你只需使用以下语句调用它:

sleep(seconds)

不必手动输入

time.sleep()

这个方法的缺点是输入太长。使用此方法,您将无法访问time库的其他功能,并且不能创建名为sleep的变量。但是,您可以创建名为time的变量。
如果您只需要模块的某些部分,则可以使用from [library] import [function] (, [function2])
同样地,您也可以这样做:
import time
time.sleep(1)

如果您想使用时间库的其他功能,例如time.clock(),只需键入time.[function]()即可。但是,请不要创建名为“time”的变量,因为它会覆盖导入。解决此问题的方法是:

import time as t

这将允许您将时间库引用为t,从而使您能够执行以下操作:

t.sleep()

这适用于任何库。


8
这基本上是有关导入的迷你教程,而原帖从未提及。这个答案可以替换为“使用 time.sleep()”。 - Corey Goldberg
@CoreyGoldberg,我认为这篇文章没有任何问题,它也解释了一些导入的内容! - William Martens

16

如果你想在Python脚本中设置时间延迟:

可以使用time.sleepEvent().wait,如下所示:

from threading import Event
from time import sleep

delay_in_sec = 2

# Use time.sleep like this
sleep(delay_in_sec)         # Returns None
print(f'slept for {delay_in_sec} seconds')

# Or use Event().wait like this
Event().wait(delay_in_sec)  # Returns False
print(f'waited for {delay_in_sec} seconds')

然而,如果你想要延迟执行一个函数,请按照以下步骤:

使用threading.Timer,像这样:

from threading import Timer

delay_in_sec = 2

def hello(delay_in_sec):
    print(f'function called after {delay_in_sec} seconds')

t = Timer(delay_in_sec, hello, [delay_in_sec])  # Hello function will be called 2 seconds later with [delay_in_sec] as the *args parameter
t.start()  # Returns None
print("Started")

输出:

Started
function called after 2 seconds

为什么要使用后一种方法?

  • 它不会停止整个脚本的执行(除了你传递给它的函数)。
  • 在启动计时器后,您还可以通过执行timer_obj.cancel()来停止它。

第一次运行正常,第二次出现错误:“RuntimeError:线程只能启动一次”。 - Saad Anees

12

asyncio.sleep

注意最近的Python版本(Python 3.4或更高版本)可以使用asyncio.sleep。它与异步编程和asyncio有关。请参阅下一个示例:

import asyncio
from datetime import datetime

@asyncio.coroutine
def countdown(iteration_name, countdown_sec):
    """
    Just count for some countdown_sec seconds and do nothing else
    """
    while countdown_sec > 0:
       print(f'{iteration_name} iterates: {countdown_sec} seconds')
       yield from asyncio.sleep(1)
       countdown_sec -= 1

loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(countdown('First Count', 2)),
         asyncio.ensure_future(countdown('Second Count', 3))]

start_time = datetime.utcnow()

# Run both methods. How much time will both run...?
loop.run_until_complete(asyncio.wait(tasks))

loop.close()

print(f'total running time: {datetime.utcnow() - start_time}')

我们可能认为在第一种方法中它将“睡眠”2秒钟,然后在第二种方法中睡眠3秒钟,总共运行时间为5秒钟。但它会打印:

total_running_time: 0:00:03.01286

建议阅读asyncio官方文档获取更多详细信息。


这为什么比time.sleep()更好? - srrvnn
尝试使用time.sleep运行类似的示例。您将无法获得相同的运行时间结果。建议阅读有关Python中的“异步”编程的内容。 - Aaron_ab
6
原问题涉及插入延迟。那个钉子需要的是锤子,而不是异步扳手 :-) - mabraham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接