python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式

时间:2022-09-18 18:50:31

(1)锁:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理。

    虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。    (Lock)

import json
from multiprocessing import Process,Lock ###### 锁 ######
import time
import random def get_ticket(i,ticket_lock):
print('我们到齐了')
time.sleep(1)
ticket_lock.acquire()
with open('text', 'r') as f:
last_ticket_info = json.load(f)
last_ticket = last_ticket_info['count']
if last_ticket > 0:
time.sleep(random.random())
last_ticket = last_ticket - 1
last_ticket_info['count'] = last_ticket
with open('text','w') as f:
json.dump(last_ticket_info,f)
print('%s号抢到了。'%i)
else:
print("%s号傻逼,没抢到"%i)
ticket_lock.release() if __name__ == '__main__':
ticket_lock = Lock()
for i in range(10):
p = Process(target=get_ticket,args=(i,ticket_lock,))
p.start() ##############
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
我们到齐了
4号傻逼,没抢到
5号傻逼,没抢到
0号傻逼,没抢到
2号傻逼,没抢到
1号傻逼,没抢到
3号傻逼,没抢到
8号傻逼,没抢到
7号傻逼,没抢到
6号傻逼,没抢到
9号傻逼,没抢到

抢票示例

(2)信号量:    (Semaphore)

from multiprocessing import Process,Semaphore    ##  信号量  ##
import time def dabaojian(i,s):
s.acquire()
print('%s号来洗脚'%i)
time.sleep(1)
s.release() if __name__ == '__main__':
s = Semaphore(4)
for i in range(10):
p = Process(target=dabaojian,args=(i,s,))
p.start() #########
5号来洗脚
0号来洗脚
1号来洗脚
4号来洗脚 2号来洗脚
3号来洗脚
7号来洗脚
6号来洗脚 8号来洗脚
9号来洗脚 Process finished with exit code 0

洗脚示例

(3)事件: 事件完成红绿灯示例    (Event)

from multiprocessing import Process,Event     ####  事件  ####
import time def taffic_lights(e):
while 1:
print('红灯亮')
time.sleep(5) e.set()
print('绿灯亮')
time.sleep(3)
e.clear() def car(i,e): if not e.is_set():
print('我们在等待。。。')
e.wait()
print('走你')
else:
print('可以走了。。') if __name__ =='__main__':
e = Event()
hld = Process(target=taffic_lights,args=(e,))
hld.start() while 1:
time.sleep(0.5) for i in range(3):
p = Process(target=car,args=(i,e,))
p.start() #################################
红灯亮
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
我们在等待。。。
绿灯亮
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
走你
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
可以走了。。
红灯亮

事件模拟完成红绿灯示例

(4)队列:进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的。队列就像一个特殊的列表,但是可以设置固定长度,并且从前面插入数据,从后面取出数据,先进先出。

Queue([maxsize]) 创建共享的进程队列。
参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
底层队列使用管道和锁实现。

queue的方法介绍:

q = Queue([maxsize])
创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道中。
Queue的实例q具有以下方法: q.get( [ block [ ,timeout ] ] )
返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。 q.get_nowait( )
同q.get(False)方法。 q.put(item [, block [,timeout ] ] )
将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。 q.qsize()
返回队列中目前项目的正确数量。此函数的结果并不可靠,因为在返回结果和在稍后程序中使用结果之间,队列中可能添加或删除了项目。在某些系统上,此方法可能引发NotImplementedError异常。 q.empty()
如果调用此方法时 q为空,返回True。如果其他进程或线程正在往队列中添加项目,结果是不可靠的。也就是说,在返回和使用结果之间,队列中可能已经加入新的项目。 q.full()
如果q已满,返回为True. 由于线程的存在,结果也可能是不可靠的(参考q.empty()方法)。。

代码示例:

from multiprocessing import Process,Queue         #####  队列  #####

q = Queue(3)

q.put(1)
print(q.full())
q.put(2)
q.put(3)
print(q.full()) print(q.get())
print(q.empty())
print(q.get())
print(q.get())
print(q.empty())
print(q.get()) while 1:
try:
q.get(False)
# q.get_nowait()
except:
print('队列目前为空') ##########################
False
True
1
False
2
3
True

队列的简单示例

子进程和父进程通过队列进行通信

from multiprocessing import Process,Queue
import time def girl(q):
print('来自boy的信息',q.get())
print('来自领导的凝视',q.get()) def boy(q):
q.put('约么?') if __name__ == '__main__':
q = Queue(5)
boy_p = Process(target=boy,args=(q,))
girl_p = Process(target=girl,args=(q,))
boy_p.start()
girl_p.start()
time.sleep(1)
q.put('好好工作,别乱搞') ##########################
来自boy的信息 约么?
来自领导的凝视 好好工作,别乱搞

子进程与父进程通过队列进行通信

生产者消费者模式:

什么是生产者消费者模式:

  生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力,并且我可以根据生产速度和消费速度来均衡一下多少个生产者可以为多少个消费者提供足够的服务,就可以开多进程等等,而这些进程都是到阻塞队列或者说是缓冲区中去获取或者添加数据。

示例:    主进程在生产者生产完毕后发送结束信号None

from multiprocessing import Process,Queue
import time def shengchan(q):
for i in range(1,11):
time.sleep(1)
print('生产了%s号包子'%i)
q.put(i) def xiaofei(q):
while 1:
time.sleep(2)
s = q.get()
if s == None:
break
else:
print('消费者吃了%s包子'%s)
if __name__ =='__main__':
q = Queue(20)
sheng_p = Process(target=shengchan,args=(q,))
sheng_p.start()
xiao_p = Process(target=xiaofei,args=(q,))
xiao_p.start()
sheng_p.join() q.put(None) ############################
生产了包子1号
消费者吃了1包子
生产了包子2号
生产了包子3号
消费者吃了2包子
生产了包子4号
生产了包子5号
消费者吃了3包子
生产了包子6号
生产了包子7号
消费者吃了4包子
生产了包子8号
生产了包子9号
消费者吃了5包子
生产了包子10号
消费者吃了6包子
消费者吃了7包子
消费者吃了8包子
消费者吃了9包子
消费者吃了10包子 Process finished with exit code 0

JoinableQueue([maxsize])

#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

   #参数介绍:
maxsize是队列中允许最大项数,省略则无大小限制。
  #方法介绍:
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止,也就是队列中的数据全部被get拿走了。

示例:JoinableQueue队列实现生产者消费者模型

import time
from multiprocessing import Process,Queue,JoinableQueue def producer(q):
for i in range(1,11):
time.sleep(0.5)
print('生产了包子%s号' % i)
q.put(i)
q.join()
print('在这里等你')
def consumer(q):
while 1:
time.sleep(1)
s = q.get()
print('消费者吃了%s包子' % s)
q.task_done() #给q对象发送一个任务结束的信号 if __name__ == '__main__':
#通过队列来模拟缓冲区,大小设置为20
q = JoinableQueue(20)
#生产者进程
pro_p = Process(target=producer,args=(q,))
pro_p.start()
#消费者进程
con_p = Process(target=consumer,args=(q,))
con_p.daemon = True #
con_p.start()
pro_p.join()
print('主进程结束') ##########################
生产了包子1号
生产了包子2号
消费者吃了1包子
生产了包子3号
生产了包子4号
消费者吃了2包子
生产了包子5号
生产了包子6号
消费者吃了3包子
生产了包子7号
消费者吃了4包子
生产了包子8号
生产了包子9号
消费者吃了5包子
生产了包子10号
消费者吃了6包子
消费者吃了7包子
消费者吃了8包子
消费者吃了9包子
消费者吃了10包子
在这里等你
主进程结束 Process finished with exit code 0

JoinableQueue队列实现生产者消费者模型

逻辑思维如下图:

python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式

python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式的更多相关文章

  1. 从头认识java-17.5 堵塞队列(以生产者消费者模式为例)

    这一章节我们来讨论一下堵塞队列.我们以下将通过生产者消费者模式来介绍堵塞队列. 1.什么是堵塞队列?(摘自于并发编程网对http://tutorials.jenkov.com/java-concurr ...

  2. python 锁 信号量 事件 队列

    什么是python 进程锁? #同步效率低,但是保证了数据安全  重点 很多时候,我们需要在多个进程中同时写一个文件,如果不加锁机制,就会导致写文件错乱 这个时候,我们可以使用multiprocess ...

  3. python 并发编程 多线程 信号量

    一 信号量 信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行 如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群 ...

  4. Python 精进版SVIP版通过队列实现一个生产者消费者模型

    import time from multiprocessing import Process,Queue,JoinableQueue #生产者 def producer(q): for i in r ...

  5. python 并发编程 多线程 目录

    线程理论 python 并发编程 多线程 开启线程的两种方式 python 并发编程 多线程与多进程的区别 python 并发编程 多线程 Thread对象的其他属性或方法 python 并发编程 多 ...

  6. Java并发(基础知识)—— 阻塞队列和生产者消费者模式

    1.阻塞队列                                                                                        Blocki ...

  7. LabVIEW之生产者/消费者模式--队列操作 彭会锋

    LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...

  8. 10 阻塞队列 & 生产者-消费者模式

    原文:http://www.cnblogs.com/dolphin0520/p/3932906.html 在前面我们接触的队列都是非阻塞队列,比如PriorityQueue.LinkedList(Li ...

  9. LabVIEW之生产者/消费者模式--队列操作

    LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户

    阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...

  2. 树形DP习题

    听闻noip要考树形DP,本蒟蒻万分惶恐,特刷一坨题目,以慰受惊之心. codevs 1486 /*和非常出名的"选课"是一个题*/ #include<cstdio> ...

  3. leetcode 题解:Search in Rotated Sorted Array II (旋转已排序数组查找2)

    题目: Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed? Would t ...

  4. 安装openshift客户端工具 rhc

    安装ruby: $ sudo apt-get install ruby-full 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 将会安装下列额外的软件包: ...

  5. cocos2dx 资源合并&period;

    文件合并之前 文件合并之后 吐槽 我们项目比较奇葩, ui用cocostudio做, 这项光荣的任务由美术接手. 这个美术是个新手, 经过我长时间的观察, 她似乎不用怎么画画. 至少在很长一段时间里, ...

  6. 使用wget下载JDK8

    每次去官网下载JDK有点烦 但是直接使用wget 又得同意协议所以 使用如下的wget就好了(注意是64位的哦) 先去官网看一下地址变化 没有如下 :修改后面的下载地址即可 注意哦~ 2.然后使用下面 ...

  7. js实现原生选项卡

        <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title ...

  8. shell脚本实例-安装httpd,安装yum源

    1.安装httpd #!/usr/bin/bash getway=192.168.1.1 ping -c1 www.baidu.com &>/dev/null if [ $? -eq 0 ...

  9. C&plus;&plus; Programming Language中的Calculator源代码

    C++ Programming Language 4th中的Calculator源代码整理,因为在C++ Programming Language中,涉及了很多文件位置之类的变化,所以,这里只是其中的 ...

  10. 个人项目——wc源程序特征统计

    这一次要做的项目是wc——统计程序文件特征的命令行程序. 根据需求需求得到的模式为:wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数与程序交互,需 ...