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

开发 后端
现在大家想一想,有没有什么办法,在不使用time.sleep的情况下,让程序暂停5秒?

我们知道,在 Python 里面可以使用time.sleep来让代码暂停一段时间,例如:

[[349670]]

  1. import time 
  2.  
  3. print('...部分代码...') 
  4. time.sleep(5) 
  5. print('...剩下的代码...') 

程序首先打印出...部分代码...,然后等待5秒钟,再打印出...剩下的代码...。

现在大家想一想,有没有什么办法,在不使用time.sleep的情况下,让程序暂停5秒?

你可能会说,用requests访问一个延迟5秒的网址、或者用递归版算法计算斐波那契数列第36位……这些奇技淫巧。

不过今天我说的,是另外一个东西,threading模块里面的Event。

我们来看看它的用法:

  1. import threading 
  2.  
  3. event = threading.Event() 
  4. print('...部分代码...') 
  5. event.wait(5) 
  6. print('...剩下的代码...') 

这样一来,程序首先打印出...部分代码...,然后等待5秒钟,再打印出...剩下的代码...。

功能看起来跟time.sleep没什么区别,那为什么我要特别提到它呢?因为在多线程里面,它比time.sleep更有用。我们来看一个例子:

  1. import threading 
  2.  
  3. class Checker(threading.Thread): 
  4.     def __init__(self, event): 
  5.         super().__init__() 
  6.         self.event = event 
  7.  
  8.     def run(self): 
  9.         while not self.event.is_set(): 
  10.             print('检查 redis 是否有数据') 
  11.             time.sleep(60) 
  12.  
  13. trigger_async_task() 
  14. event = threading.Event() 
  15. checker = Checker(event) 
  16. checker.start() 
  17. if user_cancel_task(): 
  18.     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):

  1. import threading 
  2.  
  3. class Checker(threading.Thread): 
  4.     def __init__(self, event): 
  5.         super().__init__() 
  6.         self.event = event 
  7.  
  8.     def run(self): 
  9.         while not self.event.is_set(): 
  10.             print('检查 redis 是否有数据') 
  11.             self.event.wait(60) 
  12.  
  13. trigger_task() 
  14. event = threading.Event() 
  15. checker = Checker(event) 
  16. checker.start() 
  17. if user_cancel_task(): 
  18.     event.set() 

那么,即便self.event.wait(60)刚刚开始阻塞,只要我在主线程中执行了event.set(),子线程里面的阻塞立刻就会结束。于是子线程立刻就会结束。不需要再白白等待60秒。

并且,event.wait()这个函数在底层是使用 C 语言实现的,不受 GIL 锁的干扰。

 

责任编辑:赵宁宁 来源: 未闻Code
相关推荐

2020-12-22 06:04:13

Python定时代码

2023-07-06 14:08:54

ChatGPTLLM大型语言模型

2011-06-22 15:09:34

Qt 线程 sleep

2019-11-08 09:24:35

KotlinJavaView

2022-10-31 07:09:15

拷贝代码项目

2021-08-23 11:35:37

代码开发开源

2017-01-15 14:18:35

大数据HadoopScrapy

2021-08-30 08:40:02

网页404HTTP

2016-10-26 08:57:13

HadoopScrapy大数据

2020-06-17 07:56:19

前端存储数据

2022-07-27 15:30:24

媒体查询css

2016-11-22 19:37:54

Linux恢复文件

2020-05-06 08:35:13

开源图标库

2017-12-07 15:05:50

全球互联网创新峰会

2022-12-02 08:48:16

CSS置灰网站

2020-07-29 22:46:59

容器KubernetesPaaS

2014-10-27 15:21:40

程序员代码

2020-07-07 07:55:53

web app数据科学机器学习

2021-09-27 10:03:55

装饰器代码

2009-06-06 19:15:39

imagebuffer
点赞
收藏

51CTO技术栈公众号