zoukankan      html  css  js  c++  java
  • python线程条件变量Condition(31)

         对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition.

     

    帅醒

     

    一.线程条件变量Condition相关函数介绍

        acquire() —  线程锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作;

        release() — 释放锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作;

        wait(timeout) —  线程挂起(阻塞状态),直到收到一个notify通知或者超时才会被唤醒继续运行(超时参数默认不设置,可选填,类型是浮点数,单位是秒)。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError;

        notify(n=1) —  通知其他线程,那些挂起的线程接到这个通知之后会开始运行,缺省参数,默认是通知一个正等待通知的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError,notify()不会主动释放Lock;

        notifyAll() —  如果wait状态线程比较多,notifyAll的作用就是通知所有线程;

     

    不要脸

     

     

    二.线程条件变量Condition原理

        在前面的文章已经介绍过互斥锁,主要作用是并行访问共享资源时,保护共享资源,防止出现脏数据。python 条件变量Condition也需要关联互斥锁,同时Condition自身提供了wait/notify/notifyAll方法,用于阻塞/通知其他并行线程,可以访问共享资源了。可以这么理解,Condition提供了一种多线程通信机制,假如线程1需要数据,那么线程1就阻塞等待,这时线程2就去制造数据,线程2制造好数据后,通知线程1可以去取数据了,然后线程1去获取数据。

    张飞

    三.线程条件变量Condition使用

        案例一:成语接龙

    # !usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    @Author:何以解忧
    @Blog(个人博客地址): shuopython.com
    @WeChat Official Account(微信公众号):猿说python
    @Github:www.github.com
     
    @File:python_.py
    @Time:2019/10/21 21:25
     
    @Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!
    """
     
    # 导入线程模块
    import threading
     
    # 创建条件变量condition
    con = threading.Condition()
     
    def thread_one(name):
        # 条件变量condition 线程上锁
        con.acquire()
     
        print("{}:成语接龙准备好了吗".format(name))
        # 唤醒正在等待(wait)的线程
        con.notify()
     
        # 等待对方回应消息,使用wait阻塞线程,等待对方通过notify唤醒本线程
        con.wait()
        print("{}:一干二净".format(name))
        # 唤醒对方
        con.notify()
     
        # 等待消息答应
        con.wait()
        print("{}:一天就知道看抖音美女,给你来个简单点的,来了:毛手毛脚".format(name))
        # 唤醒对方
        con.notify()
     
        # 等待消息答应
        con.wait()
        print("{}:哟哟哟,不错不错!".format(name))
        # 唤醒对方
        con.notify()
     
        # 条件变量condition 线程释放锁
        con.release()
     
    def thread_two(name):
        # 条件变量condition 线程上锁
        con.acquire()
     
        # wait阻塞状态,等待其他线程通过notify唤醒本线程
        con.wait()
        print("{}:准备好了~开始吧!".format(name))
        # 唤醒对方
        con.notify()
     
        # 等待消息答应
        con.wait()
        print("{}:净你妹啊,没法接...来个简单点的...".format(name))
        # 唤醒对方
        con.notify()
     
        # 等待消息答应
        con.wait()
        print("{}:嘿,这个我知道:脚踏实地".format(name))
        # 唤醒对方
        con.notify()
     
        con.release()
     
    if __name__ == "__main__":
     
        # 创建并初始化线程
        t1 = threading.Thread(target=thread_one,args=("A"))
        t2 = threading.Thread(target=thread_two,args=("B"))
     
        # 启动线程 -- 注意线程启动顺序,启动顺序很重要
        t2.start()
        t1.start()
     
        # 阻塞主线程,等待子线程结束
        t1.join()
        t2.join()
     
     
        print("程序结束!")

    输出结果:

    思考

        案例二:生产者与消费者模式,以吃火锅为例:一盘老肉片有10块肉,吃完了又重新往锅里加….

        生产者:往锅里加老肉片,每次加一盘(10块);

        消费者:吃煮熟的肉片,没吃一片,肉片数量减一,吃完为止;

    # 导入线程模块
    import threading
    import time
     
    # 创建条件变量condition
    con = threading.Condition()
    meat_num = 0
     
    def thread_consumers():
        # 条件变量condition 线程上锁
        con.acquire()
        
        # 全局变量声明关键字 global
        global meat_num
        meat_num = 0
     
        # 等待肉片下锅煮熟
        con.wait()
        while True:
            print("我来一块肉片...")
            meat_num -= 1
            print("剩余肉片数量:%d"%meat_num)
            time.sleep(0.5)
            if meat_num == 0:
                # 肉片吃光了,通知老板添加肉片
                print("老板,再来一份老肉片...")
                con.notify()
                # 肉片吃光了,等待肉片
                con.wait()
     
        # 条件变量condition 线程释放锁
        con.release()
     
     
    def thread_producer():
        # 条件变量condition 线程上锁
        con.acquire()
        # 全局变量声明关键字 global
        global meat_num
     
        # 肉片熟了,可以开始吃了
        meat_num = 10
        print("肉片熟了,可以开始吃了...")
        con.notify()
        while True:
            # 阻塞函数,等待肉片吃完的通知
            con.wait()
            meat_num = 10
            # 添加肉片完成,可以继续开吃
            print("添加肉片成功!当前肉片数量:%d"%meat_num)
            time.sleep(1)
            con.notify()
     
        con.release()
     
     
    if __name__ == "__main__":
        # 创建并初始化线程
        t1 = threading.Thread(target=thread_producer)
        t2 = threading.Thread(target=thread_consumers)
     
        # 启动线程 -- 注意线程启动顺序,启动顺序很重要
        t2.start()
        t1.start()
     
        # 阻塞主线程,等待子线程结束
        t1.join()
        t2.join()
     
        print("程序结束!")

        输出结果:

    肉片熟了,可以开始吃了...
    我来一块肉片...
    剩余肉片数量:9
    我来一块肉片...
    剩余肉片数量:8
    我来一块肉片...
    剩余肉片数量:7
    我来一块肉片...
    剩余肉片数量:6
    我来一块肉片...
    剩余肉片数量:5
    我来一块肉片...
    剩余肉片数量:4
    我来一块肉片...
    剩余肉片数量:3
    我来一块肉片...
    剩余肉片数量:2
    我来一块肉片...
    剩余肉片数量:1
    我来一块肉片...
    剩余肉片数量:0
    老板,再来一份老肉片...
    添加肉片成功!当前肉片数量:10
    我来一块肉片...
    剩余肉片数量:9
    我来一块肉片...
    剩余肉片数量:8
    我来一块肉片...
    剩余肉片数量:7
    .............

    注意:

        1.全局变量要声明关键字 global;

        2.注意线程的启动顺序,这个很重要;

     

    四.重点总结

        注意线程互斥锁Lock/线程事件Event/线程条件变量Condition三者的区别,场景不同,使用方式也不同,前两者一般可以作为简单的线程交互,线程条件变量Condition可以用于比较复杂的线程交互!

     

    猜你喜欢:

        1.python线程创建和参数传递

        2.python线程互斥锁Lock

        3.python线程事件Event

        4.python return逻辑判断表达式

     

        转载请注明:猿说Python » python条件变量Condition

     

    技术交流、商务合作请直接联系博主
    扫码或搜索:猿说python
    python教程公众号
    猿说python
    微信公众号 扫一扫关注
  • 相关阅读:
    微信小程序 --- 获取当前坐标
    微信小程序 --- 缓存数据
    微信小程序 --- 音乐的播放和控制
    微信小程序 --- webSocket
    微信小程序 --- 文件的上传和下载
    微信小程序 --- 选择图片和拍照
    微信小程序 --- loading提示框
    微信小程序 --- toast消息提示框
    Atitit.attilax软件研发与项目管理之道
    Atitit.attilax软件研发与项目管理之道
  • 原文地址:https://www.cnblogs.com/shuopython/p/11949666.html
Copyright © 2011-2022 走看看