我们已经知道,对公共资源进行互斥访问,可以使用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. jq局部打印插件jQuery.print.js(兼容IE8)

    /* @license * jQuery.print, version 1.5.1 * (c) Sathvik Ponangi, Doers' Guild * Licence: CC-By (http ...

  2. JavaScript浏览器检测之客户端检测

    客户端检测一共分为三种,分别为:能力检测.怪癖检测和用户代理检测,通过这三种检测方案,我们可以充分的了解当前浏览器所处系统.所支持的语法.所具有的特殊性能. 一.能力检测: 能力检测又称作为特性检测, ...

  3. BZOJ1014:[JSOI2008]火星人(Splay,hash)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam, 我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...

  4. 利用memcached实现分布式锁

    一  需求场景: (1) 需要限制用户创建提现订单的频率:目的一是防止前端bug引起的用户重复提交:二是防止并发攻击绕过提现策略(第一次提现和第二次提现门槛可能不同). (2) 需要限制秒杀下同一用户 ...

  5. 第一篇markdown笔记

    博客的样式设置 1 2 3 参考第一篇博客 参考第二篇博客 高效的写博客 博客园虽然支持markdown,但是好多快捷键都不支持,以后可以先在马克飞象上写好markdown笔记,再复制到博客上.

  6. php中session中的反序列

    1.php   键名 + 竖线 + 经过 serialize() 函数反序列处理的值2.php_binary    键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数 ...

  7. Qt中QScrollArea类的简单使用心得

           平台:windows 64位        Qt版本:5.5.1 MinGW 32bit 根据自己目前的需求简单说下怎么在QScrollArea滚动窗口中实现多个控件的滚动显示,先看看最 ...

  8. mysql服务器参数

    mysql服务器参数: 配置是从上往下读取,同一个参数项,后边的配置项会覆盖前边的配置项 mysql获取配置信息路径: 命令行参数    mysqld_safe  --datadir=/data/sq ...

  9. 在Ubuntu 18.04中安装Oracle Java JDK 8

    Webupd8 Team维护一个PPA存储库,其中包含适用于所有当前Ubuntu版本的Oracle Java 8安装程序脚本. 1.打开终端并运行命令添加PPA: sudo add-apt-repos ...

  10. Week7:SVM难点记录

    1.函数dataset3Params(),如何计算模型估计偏差的? model=svmTrain(X,y,c_array,@(x1,x2)gaussianKernel(x1,x2,sigma_arra ...