Python 多线程小技巧:比 time.sleep 更好用的暂停写法!

共 2274字,需浏览 5分钟

 ·

2020-11-02 07:30

 △点击上方Python猫”关注 ,回复“1”领取电子书

剧照:凡人修仙传

作者:kingname

来源:未闻Code

我们知道,在 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()
event = threading.Event()
checker = Checker(event)
checker.start()
if user_cancel_task():
    event.set()

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

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

猫注:原文标题《一日一技:除了time.sleep,你还有一个暂停代码的方法》

Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信(谢绝广告党,非诚勿扰!)~

近期热门文章推荐:

为什么 Python 多线程无法利用多核?
Python实现:详解LRU缓存淘汰算法
Python 命令行之旅:深入 click 之参数篇
如何保护你的 Python 代码 (一)—— 现有加密方案

感谢创作者的好文
浏览 17
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报