当前位置: 首页 > 科技观察

除了time.sleep,你还有暂停代码的方法

时间:2023-03-21 22:48:54 科技观察

我们知道在Python中,可以使用time.sleep让代码暂停一段时间,例如:importtimeprint('...partofthecode...')time.sleep(5)print('...restofthecode...')程序先打印出...partofthecode...,然后等待5秒,然后打印出……剩下的代码。...现在想一想,有没有办法不使用time.sleep,让程序暂停5秒?你可能会说,用requests去访问一个延迟5秒的url,或者用递归算法计算出斐波那契数列的第36位……这些奇怪的技巧和巧思。不过今天要说的是另外一个东西,threading模块中的Event。我们来看看它的用法:importthreadingevent=threading.Event()print('...部分代码...')event.wait(5)print('...其余代码...')像这样一个,程序先打印出...部分代码...,然后等待5秒,然后打印出...其余代码....功能好像没什么区别来自time.sleep,那我为什么要特别提到它呢?因为在多线程中,它比time.sleep更有用。我们来看一个例子:importthreadingclassChecker(threading.Thread):def__init__(self,event):super().__init__()self.event=eventdefrun(self):whilenotself.event.is_set():print('检查是否redis有数据')time.sleep(60)trigger_async_task()event=threading.Event()checker=Checker(event)checker.start()ifuser_cancel_task():event.set()我解释一下这段代码的意思。在主线程中,我调用trigger_async_task()来触发一个异步任务。这个任务不知道要多久才能完成。但是这个任务完成后,它会向Redis发送消息。只要Redis有这个消息,就知道完成了。所以我想创建一个检查器子线程,每隔60秒去Redis检查任务是否完成。如果没有完成,请暂停60秒并再次检查。但有些情况下,我不需要等待,比如用户主动取消了任务。这时,我想早点结束这个检查子线程。但是我们知道一个线程是不能从外面主动杀掉的,只能让它自己退出。所以当我执行event.set()时,子线程中的self.event.is_set()会返回False,所以循环就不会继续执行了。但是,如果某个循环刚刚开始,我会在主线程中调用event.set()。这时候子线程还在time.sleep,那么子线程需要等待60秒才能退出。但是,如果我修改代码以使用self.event.wait(60):.is_set():print('检查redis是否有数据')self.event.wait(60)trigger_task()event=threading.Event()checker=Checker(event)checker.start()ifuser_cancel_task():event.set()那么,即使self.event.wait(60)刚开始阻塞,只要我在主线程中执行event.set(),子线程中的阻塞就会立即结束。所以子线程会立即结束。无需白等60秒。而且event.wait()函数在底层是用C语言实现的,没有GIL锁的干扰。