多进程multiprocessing间通讯和数据共享

1、进程简介
io密集型的尽量使用多线程,如socketserver.

multiprocessing模块可以使用一些简单的API批量生生进程,可以实现本地和远程进程间同步,通过使用子进程而不是线程来有效避开了全局解释器锁GIL,因此,该multiprocessing模块允许程序员在给定机器上充分利用多个处理器。它可以在Unix和Windows上运行。

一个简单的例子如下:

from multiprocessing import Process

def f(name):
print ‘hello’, name

if name == ‘main’:
p = Process(target=f, args=(‘bob’,))
p.start()
p.join()
为了显示所涉及的各个进程ID,下面是一个扩展的示例:

-- coding: utf-8 --

#@Author: kangdan
#@time :2019/12/12 10:42
#@Software:PyCharm Community Edition

from multiprocessing import Process
import os

def info(title):
print(title)
print(‘module name:’, name)
if hasattr(os, ‘getppid’): # only available on Unix
print(‘parent process:’, os.getppid())
print(‘process id:’, os.getpid())

def f(name):
info(‘function f’)
print(‘hello’, name)

if name == ‘main’:
info(‘main line’)
p = Process(target=f, args=(‘bob’,))
p.start()
p.join()
输出:

2、进程间通讯和数据共享
不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

2.1、Queue队列
队列是线程和进程安全的。

from multiprocessing import Process, Queue

def f(q):
q.put([42, None, ‘hello’])

if name == ‘main’:
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # prints “[42, None, ‘hello’]”
p.join()
不可以在主程序中通过将q设置为global方式在子进程中使用,因为不同进程间数据是不共享的!!!

2.2、Pipe管道(不常用,一般使用Queue)
Pipe()函数返回通过管道连接的一对连接对象,管道默认情况下为双工(双向)。例如:

from multiprocessing import Process, Pipe

def f(conn):
conn.send([42, None, ‘hello’])
conn.close()

if name == ‘main’:
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print(parent_conn.recv()) # prints “[42, None, ‘hello’]”
p.join()
返回的两个连接对象Pipe()代表管道的两端。每个连接对象都有send()和 recv()方法(以及其他方法)。请注意,如果两个进程(或线程)试图同时从管道的同一端读取或写入管道的同一端,则管道中的数据可能会损坏。当然,不存在同时使用管道不同端的过程造成损坏的风险。

2.3、Managers
由返回的管理器对象Manager()控制着一个服务器进程,该进程保存Python对象,并允许其他进程使用代理对其进行操作。

通过返回的经理Manager()将支持类型 list,dict,Namespace,Lock, RLock,Semaphore,BoundedSemaphore, Condition,Event,Barrier, Queue,Value和Array。例如,

from multiprocessing import Process, Manager

def f(d, l):
d[1] = ‘1’
d[‘2’] = 2
d[0.25] = None
l.reverse()

if name == ‘main’:
with Manager() as manager:
d = manager.dict()
l = manager.list(range(10))

    p = Process(target=f, args=(d, l))
    p.start()
    p.join()

    print(d)
    print(l)

将打印

{0.25: None, 1: ‘1’, ‘2’: 2}
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
服务器进程管理器比使用共享内存对象更灵活,因为可以使它们支持任意对象类型。同样,单个管理器可以由网络上不同计算机上的进程共享。但是,它们比使用共享内存慢。

2.4、Lock
非递归锁对象:模拟threading.Lock。一旦进程或线程获取了锁,则随后从任何进程或线程获取锁的尝试都将阻塞,直到释放为止;否则,该锁将被释放。任何进程或线程都可能释放它。

请注意,Lock实际上这是一个工厂函数,该函数返回multiprocessing.synchronize.Lock使用默认上下文初始化的实例。

Lock支持上下文管理器协议,因此可以在with语句中使用。

from multiprocessing import Process, Lock

def f(l, i):
l.acquire()
try:
print(‘hello world’, i)
finally:
l.release()

if name == ‘main’:
lock = Lock()

for num in range(10):
    Process(target=f, args=(lock, num)).start()

2.5、Pool进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池有两种方法:

apply
apply_async
from multiprocessing import Pool,freeze_support
import time

def Foo(i):
time.sleep(2)
return i + 100

def Bar(arg):
print(’–>exec done:’, arg)

if name == ‘main’:
freeze_support()
pool = Pool(5)

for i in range(10):
    pool.apply_async(func=Foo, args=(i,), callback=Bar)#异步
    #callback回调函数,执行完Foo,会自动执行Bar,并且把Foo的返回值传给Bar参数
    # pool.apply(func=Foo, args=(i,))#同步,没有callback

print('end')
pool.close()
pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值