进程之间的通信(IPC),对列,管道,数据共享.进程池初识

进程之间的通信:

1. 对列

2. 管道

进程之间的数据共享

进程池

对列 先进先出FIFO ---维护秩序的时候用的比较多 买票  秒杀

from  queue  import  Queue

q = Queue(5)  #括号里面的数字是设置队列的长度

print(q.qsize())  #查看队列的当前长度

q.put(12)    #向队列中添加内容

q.get()      #取出内容

当队列中满了或者空了,再去填值或者取值就会阻塞.

print(q.full())  #查看队列是否满了

print(q.empty())  #查看队列是否空了

q.put_nowait(4)  #如果队列满了继续放值,则会报错.

q.get_nowait()  #如果队列空了继续取值,则会报错.

 

栈 : 先进后出  ----算法

实例 : 三级菜单

计算文件夹的总大小

 

进程之间的通信  ---  IPC

队列

from multiprocessing import Queue

q = Queue()

在多进程中 q.qsize() q.empty()  q.full()是不准的

q.empty()

q.full()

q.put_nowait()

q.put()

q.get()

q.get_nowait()

q.qsize()

 

主进程放  子进程取

from multiprocessing import Queue , Process

def con(q):

  print(q.get())

if __name__ == "__main__":

  q = Queue()

  p = Process(target=con,args=(q,))

  p.start()

  q.put(123)

子进程放  另一个子进程取

from multiprocessing import Queue , Process

def con(q):

  print(q.get())

def pro(q):

  q.put(123)

if __name__ == "__main__":

  q = Queue()

  p = Process(target=con,args=(q,))

  p.start()

  c = Process(target=pro,args=(q,))

  c.start()

生产者消费者模型 -- 解决创造(生产)数据和处理(消费)数据的效率不平衡问题

把创造数据和处理数据放在不同的进程中 , 根据他们的效率来调整进程的个数

生产数据快 消费数据慢  内存空间的浪费

消费数据快  生产数据慢  效率低下

import time,random

from multiprocessing import Process,Queue

def consumer(q,name):

  while True:

    food = q.get()

    if food == "stop" : break

    print("%s  消费了 %s"%(name,food))

    time.sleep(random.random())

def product(q,name,food,n = 10):

  for i in range(n):

    time.sleep(random.random())

    fd = food + str(i)

    print("%s 生产了%s"%(name,fd))

    q.put(fd)

if __name__ == "__main__":

  q = Queue()

  c = Process(target=consumer,args=(q,"alex""))

  c.start()

  p = Process(target=product,args=(q,"egon","美女")

  p.start()

  p.join()

  q.put("stop")

让consumer停下来的方法

  1.在所有生产者结束生产之后向队列中放入一个结束符

  2.有几个consumer就向队列中放几个结束符

  3.在消费之消费的过程中,接收到结束符,就结束消费的进程

import time,random

from multiprocessing import JoinableQueue , Process

def consumer(q,name):

  while True:

    food = q.get()

    print("%s 吃了%s"%(name,food))

    time.sleep(random.random())

    q.task_done()

def product(q,name,food,n= 10):

  for i in range(10):

    time.sleep(random.random())

    fd = food + str(i)

    print("%s 生产了%s"%(name,fd))

    q.put(fd)

  q.join(()

if __name__ == "__main__":

  q = JoinableQueue()

  p = Process(target=product,args=(q,"egon","美女"))

  p.start()

  c = Process(target=consumer,args=(q,"alex"))

  c.daemon = True

  c.start()

只有multiprocessing中的对列,才能帮助实现IPC

永远不可能出现数据不安全的情况,多个进程不会同时取走同一个数据

由于对列先进先出的特点 + 进程通信的功能 + 数据进程安全,经常用它来完成进城之间的通信

生产者消费者模型:

生产者和消费者的效率平衡的问题

内存的控制 -- 对列的长度限制

让消费者自动停下来

JoinableQueue

在消费数据的时候 : task_done

在生产端\主进程 : join

管道 : 是IPC通信的一种机制,队列就是基于管道来完成通信的,但是管道是原生的通信方式,在进程之间会产生数据不安全的情况,需要自己手动加锁来处理.管道在数据传输过程中,还涉及到一个端口管理这个需要我们在代码中处理,才能使代码更完善.

队列就是基于管道实现的

对列 : 数据是安全的

管道 : 数据是不安全的

对列 = 管道 + 锁

from multiprocessing import Pipe

left ,right = Pipe()

left.send("hello")

print(right.recv())

from multiprocessing import Pipe,Process

def consumer(left,right):

  left.close()

  while 1:

    try:

      print(right.recv())

    except EOFError:

      break

if __name__ == "__main__":

  left,right  = Queue()

  p = Process(target=consumer,args=(left,right))

  p.start()

  right.close()

  for i in range(5):

    left.send("hello")

  left.close()

EOF异常的出发:

在这一个进程中如果不在用这个端点了,应该close

这样在recv的时候,如果其他端点都被关闭了,就能够知道不会再有新的消息传进来,此时就不会在这里阻塞等待,而是抛出一个EOFError

close并不是关闭了整个管道,而是修改了操作系统对管道端点的应用计数的处理

from multiprocessing Process,Pipe

def consumer(p,name):

  left,right = p

  left.close()

  while 1:

    try:

      ba = right.recv()

    except EOFError:

      break

def product(p,seq=10):

  left,right = p

  right.close()

  for i in range(seq):

    left.send("hello")

if __name__ == "__main__":

  left,right=Pipe()

  for i in range(5):

    p = Process(target=consumer,args=((left,right),"nana"))

    p.start()

  for i in range(5):

    c = Process(target=product,args=((left,right),))

    c.start()

  left.close()

  right.close()

 

6.数据共享 : Manager模块

from multiprocessing import Manager,Process,Lock

def work(d,lock):

  with lock:

    d["count"] -= 1

if __name__ == "__main__":

  lock = Lock()

  m = Manager()  #共享数据

  dic = m.dict({"count":100})  #Manager调用字典

  pl = []

  for i in range(100):

    p = Process(target=work,args=(dic,lock))  #所有子进程共享字典

    pl.append(p)

    p.start()

  for i in pl:

    i.join()

  print(dic)

7.进程池的初识:

操作系统开启进程慢,几个CPU就能同时运行几个进程,进程的个数不是无限开启的

进程池 : 如果必须用多个进程,且是高计算性,没有IO型的程序,希望并行,最充分的使用CPU.

import os,time

from multiprocessing import Pool

def func(i):

  time.sleep(0.1)

  print(os.getpid(),i)

if __name__== "__main__":

  p = Pool(5)

  for i in range(20):

    p.apply_async(func,args=(i,))

  p.close()

  p.join()

8.总结:

IPC通信:

队列 : 管道 + 锁

管道 : 是队列的底层

数据共享 : 进程就是数据隔离的

Manager模块

数据类型都能够进行数据共享

一部分都是不加锁,不支持数据进程安全

不安全的解决办法 是加锁

进程池

进程不能无限开,会给操作系统调度增加负担

且真正能被同时执行的进程最多也就和CPU个数相同等

进程的开启和销毁都要消耗资源和时间

进程池 和信号量 :

进程池 :

进程池里有几个进程,就起几个.不管多少任务,池子里进程的个数是固定的.

开启进程和关闭进程这些事都是需要固定的时间开销 , 不会产生额外的时间开销 ; 且进程池中的进程数控制的好,那么操作系统的压力也小.

信号量 : 

有多少个任务就起多少个进程/线程

可以帮助减少操作系统切换负担 , 但是并不能帮助减少进/线程开启和关闭的时间

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

 

posted @ 2018-07-27 17:15  冯坤大神  阅读(154)  评论(0编辑  收藏  举报