开发并行程序的时候,会碰到在不同进程访问同一个对象的情况,python下面有个multiprocessing.Manager,使用这个类,可以创建共享对象(shared object),其他进程就可以通过proxy访问这个这些共享对象了。
举个例子,定义一个共享的list对象,有两个写进程入,他们每秒在这个list写入”PID:进程ID, NUM:随机数”这样的内容,一个读取进程每2秒读取这个list的内容:
import multiprocessing
import random
import time
import os
# 写入进程执行的内容
def writer(my_list):
pid = os.getpid()
while True:
time.sleep(1)
my_list.append('PID:{}, NUM:{}'.format(pid, random.randint(0, 100)))
# 读取进程执行的内容
def reader(my_list):
while True:
time.sleep(2)
if len(my_list) > 0:
print('-----------------------------')
print('\n'.join(my_list))
if __name__ == '__main__':
with multiprocessing.Manager() as manager: # 创建manager对象
my_list = manager.list() # 共享对象my_list
wp1 = multiprocessing.Process(target=writer, args=(my_list, ))
wp2 = multiprocessing.Process(target=writer, args=(my_list, ))
wp1.start()
wp2.start()
rp = multiprocessing.Process(target=reader, args=(my_list, ))
rp.start()
wp1.join()
wp2.join()
rp.join()
代码比较简单,不废话了。
Manager定义在multiprocessing.managers.py文件下面,从文件里看,Manger()指向的其实是SyncManager

SyncManager继承自BaseManager,后面定义自己的manager还会用到BaseManager这个类。
SyncManager的内容:
class SyncManager(BaseManager):
'''
Subclass of `BaseManager` which supports a number of shared object types.
The types registered are those intended for the synchronization
of threads, plus `dict`, `list` and `Namespace`.
The `multiprocessing.Manager()` function creates started instances of
this class.
'''
不是我懒,是它确实什么都没有~真的就只继承了BaseManager,SyncManager主要干的活是调用register来注册一些可以通过proxy访问的对象,比如上面我们用到的list对象,managers.py文件里是这么注册list对象的:
SyncManager.register('list', list, ListProxy)
register是BaseManager的类方法,长这样:
@classmethod
def register(cls, typeid, callable=None, proxytype=None, exposed=None,
method_to_typeid=None, create_method=True):
'''
Register a typeid with the manager type
'''
if '_registry' not in cls.__dict__:
cls._registry = cls._registry.copy()
if proxytype is None:
proxytype = AutoProxy
BaseManager类的_registry里面保存了所有注册过的类型,看下面:

如果proxytype是空的话,会调用AutoProxy。
上面扯了这么多,如果我们想共享一个自己的定义的类,怎么做?仿照SyncManger的写法就可以了,官方例子是这样的:
from multiprocessing.managers import BaseManager
class MathsClass:
def add(self, x, y):
return x + y
def mul(self, x, y):
return x * y
class MyManager(BaseManager):
pass
MyManager.register('Maths', MathsClass)
if __name__ == '__main__':
with MyManager() as manager:
maths = manager.Maths()
print(maths.add(4, 3)) # prints 7
print(maths.mul(7, 8)) # prints 56
应该还是蛮简单的,如果想在自己的manager类里面注册list,可以仿照SyncManager的写法,MyManager.register(‘list’, list, ListProxy)。