进程间通信——生产者消费者模型

  1、一些重要概念

*****  进程队列 :

*** 队列是进程安全(进程间数据安全-多个进程不能同时操作同一个文件、数据库等)的!因为它自己带锁

*** 队列,实际上是基于'文件家族的socket服务'实现的!在运行队列的文件的同目录如果创建一个名为socket.py文件的话,执行时候会报错!
    ### 文件家族的socket服务实现的额IPC机制:队列、pipe(管道,没有带锁,有安全问题)
        ### pipe(管道) = 文件家族的socket服务
        ### 队列  = pipe + 锁
    
1、进程之间通信(IPC)
    ## 进程间的通信:IPC —— inter process communication
    ## 多个进程之间的数据是隔离的
    ## 进程之间的数据交互  ———— 可以通过:网络、文件来实现的————socket来实现
    
2、进程间通信的实现方式:
    ## 通过Python模块实现进程间的通信
        ## 基于原生socket可以实现
        ## 基于进程队列也可以实现  *****
    ## 第三方的软件/工具来实现:基本都是基于网络的
        ## memcache
        ## redis
        ## rabbitMQ
        ## kafka

 2、基本的实现方法:子进程通过队列拿到主进程的值

# -*- coding:utf-8 -*-
from multiprocessing import Process,Queue

def task(q):
    # 在子进程中从队列中拿数据
    g = q.get()
    print('子进程收到:',g)

if __name__ == '__main__':
    # 实例化队列对象
    q = Queue()
    # 开进程
    process_task = Process(target=task,args=(q,))
    process_task.start()
    # 在主进程中往队列添加一个值
    q.put('wanghw')

  结果:

子进程收到: wanghw

  3、重要模型:生产者消费者模型 ——爬虫中用到:获取数据、处理数据(生产者消费者数量可变)

  简单说明:

一:需要在生产者执行完之前阻塞主线程,因此每一个生产者都加join
# 在生产者执行完之前必须阻塞主线程
# 逻辑上:producer生产完consumer可能还没有收完,
# 因此得等producer生产完最后才能往队列里put跟消费者数量一样的None

二:最后为了结束程序
# 最后往队列中添加消费者数量的None

三:一个生产数据和消费数据的完整的流程解耦成为两个部分:生产跟消费

四:由于生产速度与消费速度不一致,所以需要我们调整生产者与消费者的个数来达到效率平衡

  代码:

# -*- coding:utf-8 -*-
import time
import random
from multiprocessing import Process,Queue

def producer(name,q):
    for i in range(1,6):
        # 接收数据延迟 uniform方法必须有两个参数,这里表示0-1的任意小数
        time.sleep(random.uniform(0,1))
        data = 'data-%s'%i
        q.put(data)
        print('生产者 %s 生产了数据:%s'%(name,data))


def consumer(name,q):
    while 1:
        data = q.get()
        if data is None:
            print('\033[31;1m %s 消费完了 \033[0m'%name)
            break
        print('消费者 %s 收到数据:%s'%(name,data))
        # 模拟处理数据延迟 random可以不带参数,这里表示0-1的任意小数
        time.sleep(random.random())

if __name__ == '__main__':
    # 队列对象
    q = Queue()
    # 三个生产者 # 四个消费者
    pro_name = ['whw','naruto','sasuke']
    con_name = ['aaa','bbb','ccc','ddd']
    # 接收对象的列表
    pro_lis = []

    # 开子进程
    for i in pro_name:
        p = Process(target=producer,args=(i,q))
        p.start() # 千万别忘了 start!!!
        pro_lis.append(p)
    for i in con_name:
        p = Process(target=consumer,args=(i,q))
        p.start() # 千万别忘了 start!!!

    # 需要等待生产者全部执行完  在生产者执行完之前必须阻塞主线程
    # 逻辑上:producer生产完consumer可能还没有收完,
    # 因此得等producer生产完最后才能往队列里put跟消费者数量一样的None
    for i in pro_lis:
        i.join()

    # 最后根据消费者数量往队列中put None
    for i in range(len(con_name)):
        q.put(None)

结果:

 

posted on 2019-04-16 17:18  江湖乄夜雨  阅读(425)  评论(0编辑  收藏  举报