37 day of python

内容回顾

数据隔离

  进程和进程之间内存中的数据是互相隔离的

多进程起socket

守护进程

  守护进程会随着主进程的代码结束而结束

  报活 

锁  Lock  互斥锁

acquire / release

信息量

  锁 + 计数器

事件 : 通过一个标记来控制对多个进程进行同步控制

  在某个地方wait是否阻塞的行为是根据事件对象内部的一个标记来决定的

  在事件对象中提供的方法可以修改这个标记的状态

 

 

今日内容

进程之间的通信

  队列    *****

  管道    ***

进程之间的数据共享  *

进程池    *****

 

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

# from queue import Queue
# q = Queue(5)
# print(q.qsize())
# q.put(12)
# q.put(3)
# q.put(4)
# q.put(4)
# q.put(4)                   # 满了会阻塞 
# q.put_nowait()        # 满了就会报错
# print('***',q.qsize())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())         # 没有值的时候会阻塞
# print(q.get_nowait())  # 当有值的时候取值
# print(q.get_nowait())  # 没有值的时候会报错
# print(q.full())
# print(q.empty())
# print(q.qsize())
# print(q.get())
# print(q.get())
# print(q.qsize())    

栈  先进先出  -  算法

  三级菜单

  计算文件夹的总大小

 

 

进程之间得通信 - IPC

队列

from multiprocessing import Queue
q = Queue()

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

q.empty()
q.full()
q.put_nowait()
q.put()
q.get_nowait()
q.get()

 

主进程放 子进程取

from multiprocessing import Queue,Process
def funa(q):
    for i in range(5):
        print(q.get())

if __name__ == '__main__':
    q = Queue()
    p = Process(target=funa,args=(q,))
    for i in range(5):
        q.put(i)
    p.start()

 

 

子进程放  另一个子进程取

from multiprocessing import Queue,Process
def con(q):
    print(q.get())
def ad(q):
    q.put(123)

if __name__ == '__main__':
    q = Queue()
    p = Process(target=con,args=(q,))
    p.start()
    p1 = Process(target=ad, args=(q,))
    p1.start()

 

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

把创造数据 和 处理数据放在不同的进程中,

根据他们的效率来调整进程的个数

 

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

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

import time
import 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 producer(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(10)
    c1 = Process(target=consumer,args=(q,'alex'))
    c1.start()
    c2 = Process(target=consumer,args=(q,'alex'))
    c2.start()
    p1 = Process(target=producer,args=(q,'太白','泔水'))
    p1.start()
    p2 = Process(target=producer, args=(q, 'egon', '泔水'))
    p2.start()
    p1.join()
    p2.join()
    q.put('stop')
    q.put('stop')

让consumer停下来的方法

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

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

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

 

import time
import random
from multiprocessing import JoinableQueue,Process
# join 阻塞
def consumer(q,name):
    while True:
        food = q.get()
        print('%s 吃了 %s'%(name,food))
        time.sleep(random.random())
        q.task_done()

def producer(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)
    q.join()
if __name__ == '__main__':
    q = JoinableQueue()
    c1 = Process(target=consumer,args=(q,'alex'))
    c1.daemon = True
    c1.start()
    c2 = Process(target=consumer, args=(q, 'alex'))
    c2.daemon = True
    c2.start()
    p1 = Process(target=producer,args=(q,'太白','泔水'))
    p1.start()
    p2 = Process(target=producer, args=(q, 'egon', '鱼刺'))
    p2.start()
    p1.join()
    p2.join()

只有multiprocessing中的队列 才能帮助你 实现IPC

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

提供给你的方法

  put

  get

  put_nowait

  get_nowait

  empty    -  在多进程内不可靠

  full      -  在多进程内不可靠

  qsize     -  在多进程内不可靠

 

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

生产者消费者模型

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

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

  让消费者自动停下来

 

JoinableQueue

  在消费数据的时候  task_done

  在生产端\主进程  join

 

 

管道

队列就是基于管道实现的

队列  数据安全的

管道  数据不安全的

队列 = 管道 + 锁

from multiprocessing import Pipe
left,right = Pipe()
left.send('aaa')
print(right.recv())
from multiprocessing import Pipe,Process
def consumer(left,right):
    left.close()
    while True:
        try:
            print(right.recv())
        except EOFError:
            break

if __name__ == '__main__':
    left,right = Pipe()
    p = Process(target=consumer,args=(left,right))
    p.start()
    right.close()
    for i in range(10):
        left.send('hello')
    left.close()

EOF异常的触发

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

  这一在recv的时候,如果没有消息可接收,recv方法会一直阻塞。

  如果其他端点都被关闭了,就能够知道不会在有新的消息传进来

  此时就不会在这里阻塞等待,而是抛出一个EOFError

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

 

 

以下是错误代码:代表管道数据不安全

from multiprocessing import Process,Pipe

def consumer(p,name):
    produce,consume=p
    produce.close()
    while True:
        try:
            baozi = consume.recv()
            print('%s 收到包子:%s' %(name,baozi))
        except EOFError:
            break

def producer(p,seq=10):
    produce,consume=p
    consume.close()
    for i in range(seq):
        produce.send(i)

if __name__ == '__main__':
    produce,consume=Pipe()
    for i in range(5):
        c = Process(target=consumer,args=((produce,consume),'c1'))
        c.start()
    for i in range(5):
        p = Process(target=producer,args=((produce,consume)))
        p.start()
    producer((produce,consume))
    produce.close()
    consume.close()

 

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})
    p_l = []
    for i in range(100):
        p = Process(target=work,args=(dic,lock))
        p_l.append(p)
        p.start()
    for p in p_l:
        p.join()
    print(dic)
    

 

with as 的机制

  __enter__

  __exit__

 

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

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

 

import os
import 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()

 

IPC通信
  队列 管道+锁
  管道 是队列的底层
数据共享 _ 进程就是数据隔离的
  Manager模块
    数据类型 都能够进行数据共享
    一部分都是不加锁 不支持数据进程安全
    不安全的解决办法 加锁
进程池
  进程不能无限开 会给操作系统调度增加负担
  且真正能被同时执行的进程最多也就和CPU个数相同等
  进程的开启和销毁都要消耗资源和时间

 

posted @ 2018-07-26 22:35  贾迪123  阅读(94)  评论(0)    收藏  举报