博客
关于我
Python_生产者消费者模型、管道、数据共享、进程池
阅读量:797 次
发布时间:2023-03-09

本文共 2659 字,大约阅读时间需要 8 分钟。

生产者消费者模型、管道与数据共享的分析

生产者消费者模型

生产者消费者模型是处理数据生产与消费的经典模式,适用于分布式系统中的数据处理。生产者负责生产数据,消费者负责消费数据。这种模型通过队列进行通信,保证了数据的有序性和安全性。以下是使用Python的multiprocessing模块实现的生产者消费者模型示例:

import timeimport randomfrom multiprocessing import Process, Queuedef consumer(q):    while True:        obj = q.get()        print(f'消费了一个数据{obj}')        time.sleep(random.randint(1, 3))if __name__ == "__main__":    q = Queue()    Process(target=consumer, args=(q,)).start()    for i in range(10):        time.sleep(random.randint(1, 5))        q.put(f'food{i}')        print(f'生产了一个数据food{i}')

结果示例

运行上述代码会观察到生产者和消费者交替工作的现象,随着时间的推移,队列中的数据会被逐一消费完毕。

阻塞队列

在上述模型中,q.get()是阻塞操作,直到队列中有数据被放入为止。这保证了生产者和消费者能够高效地进行数据交换。

管道通信

管道(Pipe)是多进程间通信的基础设施,通过一个双向通道实现数据的传递。以下是一个简单的管道通信示例:

from multiprocessing import Pipe, Processdef consumer(lp, rp):    lp.close()    while True:        try:            print(rp.recv())        except EOFError:            breakif __name__ == "__main__":    lp, rp = Pipe()    Process(target=consumer, args=(lp, rp)).start()    Process(target=consumer, args=(lp, rp)).start()    Process(target=consumer, args=(lp, rp)).start()    Process(target=consumer, args=(lp, rp)).start()    Process(target=consumer, args=(lp, rp)).start()    rp.close()    for i in range(500):        lp.send(f'food{i}')    lp.close()

结果示例

运行上述代码会发现,主进程将500个“food”对象发送到管道中,随后所有进程都会退出,完成任务。

数据共享

在多进程环境下,共享数据需要谨慎处理,否则可能导致数据竞争和不一致性。普通模式下,直接使用共享数据可能会出现问题:

from multiprocessing import Manager, Process, Lockdef work(d, lock):    with lock:        d['count'] -= 1if __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)

结果示例

运行上述代码后,dic中的count会减少到0,表明所有进程都完成了工作。

上下文管理模式

为了避免数据竞争,可以使用上下文管理器:

from multiprocessing import Manager, Process, Lockdef work(d, lock):    with lock:        d['count'] -= 1if __name__ == "__main__":    with Manager() as m:        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)

结果示例

与普通模式结果一致,dic中的count减少到0。

进程池的使用

进程池提供了更高效的任务调度方式,适用于需要多进程执行的任务。以下是一个使用进程池的示例:

import osimport timedef wahaha(num):    print(f'子{os.getpid()}')    return num ** numdef call(argv):    print(f'主{os.getpid()}')    print(argv)if __name__ == "__main__":    print('主', os.getpid())    p = Pool(5)    p.apply_async(func=wahaha, args=(50,), callback=call)    p.close()    p.join()

结果示例

运行上述代码会看到主进程和子进程交替输出信息,最终所有任务完成后,进程池关闭。

转载地址:http://djlfk.baihongyu.com/

你可能感兴趣的文章
Python 入门开发学习笔记之数据的增删改查
查看>>
Python 内存管理
查看>>
Python 内嵌函数:它们有什么用处?
查看>>
python 利用pyttsx3文字转语音
查看>>
Python 基础语法:基本数据类型(一)
查看>>
Python 基础语法:基本数据类型(集合)
查看>>
python 堆排序
查看>>
python 复习计划
查看>>
Python 多处理 apply_async 永远不会在 Windows 7 上返回结果
查看>>
Python 多处理 Numpy 随机
查看>>
Python 多处理 >= 125 列表永远不会完成
查看>>
Python 多处理:在第一个子错误时中止映射
查看>>
Python 多处理不断产生 pythonw.exe 进程而不做任何实际工作
查看>>
Python 多处理从不加入
查看>>
Python 多处理如何优雅地退出?
查看>>
Python 多处理将子进程的标准输出重定向到 Tkinter 文本
查看>>
Python 多处理库错误(AttributeError:__exit__)
查看>>
Python 多处理模块的 .join() 方法到底在做什么?
查看>>
python 多线程与GIL
查看>>
Python 字符串总结
查看>>