一、互斥锁

进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理。

注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改,没错,速度是慢了,牺牲了速度而保证了数据安全。

1.上厕所的小例子:你上厕所的时候肯定得锁门吧,有人来了看见门锁着,就会在外面等着,等你吧门开开出来的时候,下一个人才去上厕所。

 Process,Lock
os
time
work(mutex):
mutex.acquire()
os.getpid())
)
os.getpid())
mutex.release()
:
Lock()
(mutex,))
(mutex,))
(mutex,))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
')

二、模拟抢票(也是利用了互斥锁的原理  :LOCK互斥锁)

 json
time
random
os
Process,Lock
chakan():
先查看票数,也就是打开那个文件
查看剩余的票数
buy():
,))
如果还有票
就修改里面的值-1
执行里面买票的一系列操作就先不执行了,让睡一会代替(并且随机的睡)
))
当前的那个id购票成功
抢票
因为查看的时候大家都可以看到,不需要加锁
加锁
买的时候必须一个一个的买,先等一个人买完了,后面的人在买
取消锁
:
Lock()
让50个人去访问那个票数
(mutex,))
25 p.start()

三、Process对象的其他属性

p.daemon :守护进程(必须在开启之前设置守护进程):如果父进程死,子进程p也死了

p.join:父进程等p执行完了才运行主进程,是父进程阻塞在原地,而p仍然在后台运行。

terminate:强制关闭。(确保p里面没有其他子进程的时候关闭,如果里面有子进程,你去用这个方法强制关闭了就会产生僵尸进程(打个比方:如果你老子挂了,你还没挂,那么就没人给你收尸了,啊哈哈))

is_alive:关闭进程的时候,不会立即关闭,所以is_alive立刻查看的结果可能还是存活

p.join():父进程在等p的结束,是父进程阻塞在原地,而p仍然在后台运行

p.name:查看名字

p.pid :查看id

我们可以简单介绍一下僵尸进程:

子进程运行完成,但是父进程迟迟没有进行回收,此时子进程实际上并没有退出,其仍然占用着系统资源,这样的⼦进程称为僵尸进程

因为僵尸进程的资源一直未被回收,造成了系统资源的浪费,过多的僵尸进程将造成系统性能下降,所以应避免出现僵⼫进程。

 Process
os
time
work():
os.getpid())
)
:
work)
work)
work)
p1.daemon = True
p2.daemon = True #守护进程(守护他爹)
p3.daemon = True #主进程死了子进程也死了(就不会执行子进程了)
p1.start()
p2.start()
p3.start()
17
p3.join()
p2.join()
多个join就是在等花费时间最长的那个运行完就执行主程序了
)
22
-了解方法---------------
p1.terminate() #强制关闭进程
time.sleep(3)
print(p1.is_alive()) #看是不是还活着
print(p1.name) #查看进程名字
print(p1.pid) #查看id号
print('主程序')

三、进程间的三种通信(IPC)方式:

 方式一:队列(推荐使用)

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

1.队列:队列类似于一条管道,元素先进先出
需要注意的一点是:队列都是在内存中操作,进程退出,队列清空,另外,队列也是一个阻塞的形态
2.队列分类
队列有很多种,但都依赖与模块queue
queue.Queue() #先进先出
queue.LifoQueue() #后进先出
queue.PriorityQueue() #优先级队列
queue.deque() #双线队列

创建队列的类(底层就是以管道和锁定的方式实现):

Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,
可以使用Queue实现多进程之间的数据传递。

参数介绍:

1 maxsize是队列中允许最大项数,省略则无大小限制。  

方法介绍:

q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常. q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False) q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

应用:

 1.可以往队列里放任意类型的
2.先进先出
Process,Queue
)
默认block=True
)
)
8
(q.get())
(q.get())
print(q.get())

队列

生产者和消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

基于队列实现生产者消费者模型

一个生产者和一个消费者(有两种方式)

1、q.put(None):生产者给放一个None进去

 Process,Queue
os
time
random
首先得有生产者和消费者
生产者制造包子
这种用 q.put(None)放进去一个None的方法虽然解决了问题
但是如果有多个生产者多个消费者,或许框里面没有包子了但是
还有其他的食物呢,你就已经显示空着,这样也可以解决,就是不完美,
'''
producter(q):
):
生产包子得有个过程,就先让睡一会
生产了这么多的包子
吧生产出来的包子放进框里面去
(os.getpid(),res))
只有生产者才知道什么时候就生产完了(放一个None进去说明此时已经生产完了)
消费者吃包子
consumer(q):
假如消费者不断的吃
q.get()
如果吃的时候框里面已经空了,就直接break了
))
(os.getpid(),res))
:
Queue()
(q,))
(q,))
p1.start()
p2.start()
p1.join()
等待执行完上面的进程,在去执行主
')

生产者与消费者1

2、利用JoinableQueue

 Process,JoinableQueue
os
time
random
首先得有生产者和消费者
消费者吃包子
consumer(q):
'''
假如消费者不断的吃
q.get()
))
(os.getpid(),res))
任务结束了(消费者告诉生产者,我已经吧东西取走了)
生产者制造包子
producter(q):
'''
):
生产包子得有个过程,就先让睡一会
生产了这么多的包子
吧生产出来的包子放进框里面去
(os.getpid(),res))
q.join()
23
:
JoinableQueue()
(q,))
(q,))
在启动之前吧消费者设置成守护进程,p1结束了p2也就结束了
p1.start()
p2.start()
在等生产者结束(生产者结束后,就不制造包子了,那消费者一直在吃,就卡住了
都不生产了还吃啥,就把消费者也结束了 )
等待执行完上面的进程,在去执行主
')

生产者和消费者2

多个生产者和多个消费者(有两种方式)

1、q.put(None):生产者给放一个None进去

多生产者与多消费者1

2、利用JoinableQueue

 Process,JoinableQueue
os
time
random
首先得有生产者和消费者
消费者吃包子
consumer(q):
True:
q.get()
))
(os.getpid(),res))
任务结束了(消费者告诉生产者,我已经吧东西取走了)
product_baozi(q):
):
)
i
q.put(res)
(os.getpid(), res))
不用put(None) 了,在等q被取完。(如果数据没有被取完,生产者就不会结束掉)
product_gutou(q):
):
)
i
q.put(res)
(os.getpid(), res))
q.join()
product_doujiang(q):
):
)
i
q.put(res)
(os.getpid(), res))
q.join()
34
:
JoinableQueue()
生产者们:厨师们
(q,))
(q,))
(q,))
41
消费者们:吃货们
(q,))
(q,))
True
True
p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
[p1,p2,p3,p4,p5]
li:
i.start()
p1.join()
p2.join()
p3.join()
')

多生产者与多消费2

  方式二:管道(不推荐使用,了解即可)

管道相当于队列,但是管道不自动加锁

  方式三:共享数据(不推荐使用,了解即可)

共享数据也没有自动加锁的功能,所以还是推荐用队列的。感兴趣的可以研究研究管道和共享数据

python并发编程之多进程1互斥锁与进程间的通信的更多相关文章

  1. python并发编程之多进程1--(互斥锁与进程间的通信)

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  2. python并发编程之多进程1-----------互斥锁与进程间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  3. python并发编程之多进程2-------------数据共享及进程池和回调函数

    一.数据共享 1.进程间的通信应该尽量避免共享数据的方式 2.进程间的数据是独立的,可以借助队列或管道实现通信,二者都是基于消息传递的. 虽然进程间数据独立,但可以用过Manager实现数据共享,事实 ...

  4. python并发编程之多进程(三):共享数据&进程池

    一,共享数据 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合 通过消息队列交换数据.这样极大地减少了对使用锁定和其他同步手段的需求, 还可以扩展 ...

  5. Python之网路编程之-互斥锁与进程间的通信(IPC)及生产者消费者模型

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  6. Python并发编程__多进程

    Python并发编程_多进程 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大 ...

  7. Python进阶(4)_进程与线程 (python并发编程之多进程)

    一.python并发编程之多进程 1.1 multiprocessing模块介绍 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大 ...

  8. python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程

    python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 目录 python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 ...

  9. python并发编程之多进程2-(数据共享及进程池和回调函数)

    一.数据共享 1.进程间的通信应该尽量避免共享数据的方式 2.进程间的数据是独立的,可以借助队列或管道实现通信,二者都是基于消息传递的. 虽然进程间数据独立,但可以用过Manager实现数据共享,事实 ...

随机推荐

  1. Python 面试题(下)

    接上篇. 网络 1 三次握手 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三路握手的一部分.客户端把这段连接的序号设定为随机数 A. 服务器端应当为一个合法的SYN回送一个SYN/ACK ...

  2. shell基础part1

    shell基础一 一.什么是shell shell是个功能强大的编程语言,也是个解释执行的脚本语言(命令解释器). 二.shell分类 1.bourne shell (包括sh.ksh.Bash.ps ...

  3. putty screen

    http://www.cnblogs.com/xupeizhi/archive/2013/05/20/3088779.html screen 会创建一个跑着shell的单一窗口 Ctrl+a d退出刚 ...

  4. iOS 基本数据类型 和 指针 特点

    基本数据类型 : 整型int, 字符型char , 浮点型 (float 和 double), 枚举型; -- 构造类型 : 数组类型, 结构体类型, 共用体类型; -- 指针类型 : 最终要的数据类 ...

  5. P3506 [POI2010]MOT-Monotonicity 2

    题目 P3506 [POI2010]MOT-Monotonicity 2 第一次切掉没题解的题\(qwq\) 做法 首先确定\(a_i\)的位置后显然就能确定\(a_{i+1}\)的位置,建一棵权值线 ...

  6. 20145229吴姗珊《Java程序设计》第二周学习总结

    教材学习内容总结 一.类型.变量与运算符 1.类型 整数:可细分为short整数.int整数和long整数.不同长度的整数可储存的整数范围也不同. 字节:byte类型顾名思义.长度就是一字节,需要逐字 ...

  7. Ubuntu 16.04 NFS搭建

    NFS服务器配置: 1.安装NFS相关包 apt-get install nfs-kernel-server nfs-common # centos 7# yum install nfs-utils ...

  8. B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序

    B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序 select a.*,count(*) as c from a left join b on a.id=b.ai ...

  9. C++判断一个文件是否可以正确打开的代码

    /* fopen example */ #include <iostream> #include <conio.h> using namespace std; int main ...

  10. Codeforces 463D Gargari and Permutations:隐式图dp【多串LCS】

    题目链接:http://codeforces.com/problemset/problem/463/D 题意: 给你k个1到n的排列,问你它们的LCS(最长公共子序列)是多长. 题解: 因为都是1到n ...