我们已经知道,对公共资源进行互斥访问,可以使用Lock上锁,或者使用RLock去重入锁。

但是这些都只是方便于处理简单的同步现象,我们甚至还不能很合理的去解决使用Lock锁带来的死锁问题。

要解决更复杂的同步问题,就必须考虑别的办法了。

threading提供的Condition对象提供了对复杂线程同步问题的支持。

Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。

使用Condition的主要方式为:

线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些 处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问 题。

下面我们通过很著名的“生产者-消费者”模型来来演示下,在Python中使用Condition实现复杂同步。

生产者和消费者,各一个线程,双方将会围绕products来产生同步问题,首先是2个生成者生产products ,而接下来的10个消费者将会消耗products

import threading
import time condition = threading.Condition()
products = 0 class Producer(threading.Thread):
'''生产者'''
ix = [0] # 生产者实例个数
# 闭包,必须是数组,不能直接 ix = 0
def __init__(self, ix=0):
super().__init__()
self.ix[0] += 1
self.setName('生产者' + str(self.ix[0])) def run(self):
global condition, products while True:
if condition.acquire():
if products < 10:
products += 1;
print("{}:库存不足(10-)。我努力生产了1件产品,现在产品总数量 {}".format(self.getName(), products))
condition.notify()
else:
print("{}:库存充足(10+)。让我休息会儿,现在产品总数量 {}".format(self.getName(), products))
condition.wait();
condition.release()
time.sleep(2) class Consumer(threading.Thread):
'''消费者'''
ix = [0] # 消费者实例个数
# 闭包,必须是数组,不能直接 ix = 0
def __init__(self):
super().__init__()
self.ix[0] += 1
self.setName('消费者' + str(self.ix[0])) def run(self):
global condition, products while True:
if condition.acquire():
if products > 1:
products -= 1
print("{}:我消费了1件产品,现在产品数量 {}".format(self.getName(), products))
condition.notify()
else:
print("{}:只剩下1件产品,我停止消费。现在产品数量 {}".format(self.getName(), products))
condition.wait();
condition.release()
time.sleep(2) if __name__ == "__main__":
for i in range(2):
p = Producer()
p.start() for i in range(10):
c = Consumer()
c.start()

另外:

Condition对象的构造函数可以接受一个Lock/RLock对象作为参数,

如果没有指定,则Condition对象会在内部自行创建一个 RLock;

除了notify方法外,Condition对象还提供了notifyAll方法,可以通知waiting池中的所有线程尝试acquire 内部锁。

由于上述机制,处于waiting状态的线程只能通过notify方法唤醒,所以notifyAll的作用在于防止有线程永远处于沉默状态。

python 多线程笔记(5)-- 生产者/消费者模式的更多相关文章

  1. 2.5多线程(Java学习笔记)生产者消费者模式

    一.什么是生产者消费者模式 生产者生产数据存放在缓冲区,消费者从缓冲区拿出数据处理. 可能大家会问这样有何好处? 1.解耦 由于有了缓冲区,生产者和消费者之间不直接依赖,耦合度降低,便于程序拓展和维护 ...

  2. java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

    java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样 ...

  3. 多线程学习之三生产者消费者模式Guarded Suspension

    Guarded Suspension[生产消费者模式] 一:guarded suspension的参与者--->guardedObject(被防卫)参与者                1.1该 ...

  4. JAVA多线程编程之生产者消费者模式

    Java中有一个BlockingQueue可以用来充当堵塞队列,下面是一个桌面搜索的设计 package net.jcip.examples; import java.io.File; import ...

  5. python 多线程笔记(6)-- 生产者/消费者模式(续)

    用 threading.Event() 也可以实现生产者/消费者模式 (自己拍脑袋想出来的,无法知道其正确性,请大神告知为谢!) import threading import time import ...

  6. .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法

    1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...

  7. 【多线程】--生产者消费者模式--Lock版本

    在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...

  8. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  9. java多线程系列15 设计模式 生产者 - 消费者模式

    生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...

  10. Java多线程-----实现生产者消费者模式的几种方式

       1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理 ...

随机推荐

  1. ssrf绕过记录

    第一道题来自2018 上海市大学生网络安全大赛线上赛web01 if(isset($_POST['url']) && parse_url($_POST['url'])['host']= ...

  2. python之获取文件夹下文件的绝对路径

    #!/usr/bin/python #-*-conding:utf-8-*- #获取目录下文件的绝对路径 import os def getabsroute(path): listdir = os.l ...

  3. VC++获取一个GB级大文件的字节大小

    常规的获得小文件(2.1GB以下)的字节大小可以使用ftell,函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数.使用fseek函数后再调用函数ftell()就能非常容易地确定文 ...

  4. [转]DbHelper通用数据库访问帮助类

    之前我一直都是在博客园中查看各位高手的博文,确实学到了不少知识,不过比较少写博客,现在就把我自己在项目实施过程中使用到比较好的技术框架写出来,希望能让更多的人了解和学习. 通常我们在开发使用数据库访问 ...

  5. Shell笔记-02

    Shell支持自定义变量. 定义变量 定义变量时,变量名不加美元符号($),如: variableName="value" 注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编 ...

  6. ansible实用例子

    寻找/etc/ 名为"hosts" 递归查找 ansible webserver -m find -a ' path=/etc/ file_type=any recurse=yes ...

  7. 利用PDCA工具改进周例会

    PDCA简介 PDCA循环又叫戴明环,是美国质量管理专家休哈特博士首先提出的,由戴明采纳.宣传,获得普及,从而也被称为“戴明环”. PDCA最早用来解决全面质量管理问题,但是PDCA也可以用来作为一个 ...

  8. 爬虫实战:汽车之家配置页面 破解伪元素和混淆JS

    本篇介绍如何破解汽车之家配置页面的伪元素和混淆的JS. ** 温馨提示:如需转载本文,请注明内容出处.** 本文链接:https://www.cnblogs.com/grom/p/9242156.ht ...

  9. Oracle下通过EXPDP导出某用户下的所有表,实例

    一开始在所数据库表导入,导出的时候,经常发现含有BLOB等大数据类型文件无法简单正常的导入导出(imp/dmp),然后在网上得知oracle 10以后有了(impdp/dmpdp)命令,数据导入导出的 ...

  10. Java并发编程(七)终结线程

    线程的状态 一个线程会有如下五个状态 1.新建:线程在被创建时会暂时处于这种状态,此时系统为线程分配资源并对其进行初始化 2.就绪:此时线程已经可以运行,只是系统没有为其分配CPU时间. 3.运行:系 ...