一日一技:除了 time.sleep,你还有一个暂停代码的方法
我们知道,在 Python 里面可以使用
time.sleep
来让代码暂停一段时间,例如:
import time
print('...部分代码...')
time.sleep(5)
print('...剩下的代码...')
程序首先打印出
...部分代码...
,然后等待5秒钟,再打印出
...剩下的代码...
。
现在大家想一想,有没有什么办法,在不使用
time.sleep
的情况下,让程序暂停5秒?
你可能会说,用
requests
访问一个延迟5秒的网址、或者用递归版算法计算斐波那契数列第36位……这些奇技淫巧。
不过今天我说的,是另外一个东西,
threading
模块里面的
Event
。
我们来看看它的用法:
import threading
event = threading.Event()
print('...部分代码...')
event.wait(5)
print('...剩下的代码...')
这样一来,程序首先打印出
...部分代码...
,然后等待5秒钟,再打印出
...剩下的代码...
。
功能看起来跟
time.sleep
没什么区别,那为什么我要特别提到它呢?因为在多线程里面,它比
time.sleep
更有用。我们来看一个例子:
import threading
class Checker(threading.Thread):
def __init__(self, event):
super().__init__()
self.event = event
def run(self):
while not self.event.is_set():
print('检查 redis 是否有数据')
time.sleep(60)
trigger_async_task()
event = threading.Event()
checker = Checker(event)
checker.start()
if user_cancel_task():
event.set()
我来解释一下这段代码的意思。在主线程里面,我调用
trigger_async_task()
触发了一个异步任务。这个任务多久完成我并不清楚。但是这个任务完成以后,它会往
Redis
里面发送一条消息,只要 Redis 有这个消息了,我就知道它完成了。所以我要创建一个 checker 子线程,每60秒去 Redis里面检查任务是否完成。如果没有完成,就暂停60秒,然后再检查。
但某些情况下,我不需要等待了,例如用户主动取消了任务。这个时候,我就想提前结束这个 checker 子线程。
但是我们知道,线程是不能从外面主动杀死的,只能让它自己退出。所以当我执行
event.set()
后,子线程里面
self.event.is_set()
就会返回 False,于是这个循环就不会继续执行了。
可是,如果某一轮循环刚刚开始,我在主线程里面调用了
event.set()
。此时,子线程还在
time.sleep
中,那么子线程需要等待60秒才会退出。
但如果我修改一下代码,使用
self.event.wait(60)
:
import threading
class Checker(threading.Thread):
def __init__(self, event):
super().__init__()
self.event = event
def run(self):
while not self.event.is_set():
print('检查 redis 是否有数据')
self.event.wait(60)
trigger_task()