🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

【Python time】入门:从使用sleep等待到通过perf_counter精确计时

要在电脑上通过命令提示符或 PowerShell 运行 Python,需要先下载并安装 Python。
如果你还没有安装,请参考Python安装与开发环境配置一文来完成安装。

你好!我是一位与AI一同学习编程,并用一个半月时间创建了两个网站的专家。就在几个月前,我和大家一样,也是一个编程知识为零的初学者。

在学习Python的过程中,你是否经常在AI生成的代码或其他人的示例代码中看到 `import time` 这行描述?可能很多人会觉得,“又看到 `time` 了,这到底能做什么?”“只是用来停止或测量时间的吗?”

在本文中,我将结合自己实际遇到的困难,用通俗易懂的方式为初学者详细解读 `time` 模块。特别是,我们将重点关注在网站制作和数据收集中必不可少的“暂停处理(休眠)”方法和“精确测量处理所用时间”的方法。读完本文后,你应该就能自如地操控 `time` 模块了!


1. 为什么需要操作“时间”?——等待的重要性

你是否认为程序运行得越快越好?实际上,在某些情况下,“刻意等待”变得非常重要。我将介绍两个我在开发网站时遇到的具体案例。

案例1:从网站收集信息(网络爬虫)

当我们试图自动从某个网站收集信息时,程序会以人类无法想象的速度连续访问页面。这样一来,短时间内会有大量访问集中到对方服务器,造成巨大负担。这就像一大群人涌入商店妨碍营业一样。在最坏的情况下,我们的访问可能会被屏蔽。

这时,“等待”的技术就派上用场了。通过在访问一个页面后等待几秒钟的处理,可以大幅减轻服务器的负担,从而实现有礼貌的信息收集。

案例2:使用API

在使用提供天气信息、地图信息等的外部服务(API)时,“时间”管理也必不可少。许多API都设有使用次数限制(速率限制),例如“每分钟最多60次”。如果发送的请求超过此限制,服务可能会暂时无法使用,或者返回错误。

在这里,同样通过每次发送请求后等待一定时间,就可以将请求次数控制在限制范围内。

像这样,在程序中设置有意的“等待时间”的处理被称为休眠处理。而在Python中最简单实现这一功能的就是 `time.sleep()` 函数。


2. 精准等待!使用 `time.sleep()` 暂停处理

`time.sleep()` 是一个非常简单的函数,它能让程序的执行暂停指定的秒数。让我们先来看看它的基本用法。

以下代码是一个简单的示例,它会先显示“开始处理。”,然后在3秒后显示“3秒过去了。处理结束。”。请复制粘贴到你的环境中运行一下,这样你就能体会到“等待”的感觉了。


# 导入time模块
import time

print("开始处理。")

# 暂停处理3秒钟
time.sleep(3)

print("3秒过去了。处理结束。")
        

参数也可以指定小数,如0.5(0.5秒)或0.1(100毫秒)。这使得更精细的时间控制成为可能。


import time

print("只等待0.5秒。")

# 暂停处理0.5秒钟
time.sleep(0.5)

print("完成!")
        

与循环处理结合使用,可以轻松创建定期执行某项任务的程序。例如,一个每秒倒计时的程序如下所示。


import time

print("倒计时开始!")

for i in range(5, 0, -1):
    print(i)
    # 等待1秒
    time.sleep(1)

print("发射!")
        

3. 秒表功能!如何精确测量处理时间

`time` 模块的另一个重要作用是测量处理时间。了解自己代码的哪一部分耗时较长,是性能优化的第一步。

当你感觉“这个处理有点慢……”时,重要的是通过实际测量时间来确定瓶颈,而不是凭感觉判断。

新手常犯的错误方法: `time.time()`

测量时间最基本的方法是在处理开始前和结束后调用 `time.time()`,然后计算它们的差值。`time.time()` 返回自“UNIX纪元”(1970年1月1日0时0分0秒)以来的秒数。


import time

# 记录处理开始前的时间
start_time = time.time()

# 在这里写下你想要测量时间的处理
# 举例来说,我们放入一个等待1秒的处理
print("执行测量中的处理...")
time.sleep(1)
print("处理完成。")

# 记录处理结束后的时间
end_time = time.time()

# 计算并显示经过的时间
elapsed_time = end_time - start_time
print(f"处理所用时间: {elapsed_time} 秒")
        

【我的失败谈】`time.time()`的陷阱

实际上,这个 `time.time()` 虽然方便,但有一个很大的陷阱。那就是,它会受到PC系统时间变更的影响

在我刚开始学习的时候,也曾用 `time.time()` 来测量耗时较长的处理。但是,在处理过程中,PC自动进行了时间校准(NTP同步),导致得出的结果与实际处理时间完全不同,非常奇怪。例如,如果在处理过程中系统时间倒退了1秒,那么计算出的经过时间就会减少1秒。这样是无法进行准确测量的,对吧?

于是,更可靠的时间测量方法就登场了。

专业人士使用的方法: `time.perf_counter()`

`time.perf_counter()`(performance counter的缩写)是一个专门用于测量短时间间隔的函数,正如其名,非常适合测量处理时间。该函数返回的值不是具体的“时刻”,而是操作系统提供的精度最高的单调递增时间

“单调递增”是关键点,这意味着即使PC的系统时间发生变更,它也绝不会倒退。因此,即使在处理过程中发生时间同步,也不会影响测量结果。

在Python的官方文档中,也推荐使用 `perf_counter()` 来测量处理时间。

其用法与 `time.time()` 完全相同。


import time

# 记录处理开始前的计数器值
start_counter = time.perf_counter()

# 在这里写下你想要测量时间的处理
print("执行测量中的处理...")
total = 0
for i in range(10000000): # 一个耗时处理的例子
    total += i
print("处理完成。")

# 记录处理结束后的计数器值
end_counter = time.perf_counter()

# 计算并显示经过的时间
elapsed_time = end_counter - start_counter
print(f"处理所用时间: {elapsed_time} 秒")
        

除非有特殊原因,否则在测量处理时间时,记住使用 `time.perf_counter()` 就绝对不会错!


4. 【应用篇】面向Web创作者!一个完整可运行的HTML计时器

到目前为止,我们已经学习了Python的 `time` 模块。这些在服务器端(后端)运行的程序中非常有用。但是,作为Web创作者,我们希望将结果以用户可见的形式,也就是在网页上展示出来,对吧?

因此,让我们应用Python `time` 模块的思想,用HTML和JavaScript制作一个在浏览器上运行的简单倒计时器。就像Python的 `time.sleep(1)` 是“等待1秒”的命令一样,在JavaScript中,我们可以使用 `setInterval()` 命令来实现“每秒执行一次某事”。

以下代码是一个完整的HTML文件。请复制这段代码,保存为 `timer.html` 这样的文件名,然后在浏览器中打开它。按下按钮后,你应该能看到屏幕上的数字每秒减少。这正是让用户体验“可运行”程序的第一步!


<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>倒计时器</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #121212;
            color: #e0e0e0;
            font-family: sans-serif;
            text-align: center;
        }
        #timer-display {
            font-size: 8rem;
            font-weight: bold;
            color: #669df6;
        }
        button {
            margin-top: 2rem;
            padding: 1rem 2rem;
            font-size: 1.5rem;
            cursor: pointer;
            border: 1px solid #5f6368;
            background-color: transparent;
            color: #8ab4f8;
            border-radius: 5px;
        }
        button:disabled {
            cursor: not-allowed;
            opacity: 0.5;
        }
    </style>
</head>
<body>
    <div>
        <h1>用JavaScript制作倒计时</h1>
        <div id="timer-display">10</div>
        <button id="start-btn">开始</button>
        <p>应用Python time.sleep()的思想!</p>
    </div>

    <script>
        // script标签在这里编写
        const timerDisplay = document.getElementById('timer-display');
        const startButton = document.getElementById('start-btn');
        let timeLeft = 10;
        let timerId = null;

        function startTimer() {
            // 禁用按钮以防止重复点击
            startButton.disabled = true;

            // 每1秒(1000毫秒)执行一次处理
            timerId = setInterval(() => {
                timeLeft--;
                timerDisplay.textContent = timeLeft;

                if (timeLeft <= 0) {
                    clearInterval(timerId); // 停止计时器
                    timerDisplay.textContent = "Go!";
                }
            }, 1000);
        }

        // 当开始按钮被点击时,启动计时器
        startButton.addEventListener('click', startTimer);
    </script>
</body>
</html>
        

5. 使用 `time` 模块的注意事项总结

最后,让我们再次确认一下使用 `time` 模块时的要点。


总结

这次,我们学习了如何使用Python的 `time` 模块来“等待”和“测量”处理。虽然它看起来是一个不起眼的模块,但在制作实用程序时,它是一个不可或缺且非常强大的工具。

特别是 `time.sleep()` 是一个关系到对他人(服务器)体谅的重要功能,而 `time.perf_counter()` 则关系到对自己(代码性能改进)的体谅。

请活用今天学到的知识,尝试将“时间”这一概念引入到你的程序中。相信你能够创造的东西的范围一定会大大拓宽。

进入下一步

掌握了用 `time` 模块处理时间后,接下来要不要学习一下高效处理数据的便利工具呢?Python中还有很多可以标准使用的强大数据结构。

在下一篇文章中,我们将聚焦于 `collections` 模块,介绍如 `defaultdict` 和 `deque` 这样能让字典(dictionary)和列表(list)更加便利的功能。熟练运用它们,你就能写出更精炼的代码了!

» collections模块中便利的数据结构总结