最近有需求为python下多进程共享同一个变量,并且变量不仅仅是只进行读取,还要进行修改,修改后需要保证其他进程里面能读取到修改后的值。变量是一个类对象,普通的共享方式可以实现固定值或数据的共享,在共享类对象的时候出现了点问题。查阅资料后解决方式及思路如下。

思路:
通过manager.register进行注册类
注册完后,对各个进程传入类的实例
详细过程见演示代码注释

演示代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import multiprocessing
from multiprocessing.managers import BaseManager
import threading
import time

# 锁可以通过global也可以在Process中传无所谓
share_lock = threading.Lock()


# 定义一个要共享实例化对象的类
class Test():
def __init__(self):
self.test_data = "init"

def print_test_list(self, process_name):
while True:
print(f"{process_name} : Data is : {self.test_data}")
time.sleep(2)

def set_test_list(self, process_name, data):
print(f"{process_name} : modify var")
self.test_data = data


# 查看共享的类成员当前的值
def view_var(process_name, obj):
obj.print_test_list(f"{process_name}")


# 模拟一个进程修改共享的类对象
def modify_var(process_name, obj):
obj.set_test_list(process_name, "process modify")


# 主进程
def main_process():
# 如果是想注册open方法这样操作
# manager = BaseManager()
# # 一定要在start前注册,不然就注册无效
# manager.register('open', open)
# manager.start()
# obj = manager.open("1.txt","a")

# 为了更加直接我们直接以一个Test类的实例化对象来演示
manager = BaseManager()
# 一定要在start前注册,不然就注册无效
manager.register('Test', Test) # 第一个参数为类型id,通常和第二个参数传入的类的类名相同,直观并且便于阅读
manager.start()
obj = manager.Test()

process_list = []
# 创建进程1,用于不断显示共享类对象的成员变量值
process_name = "process 1"
tmp_process = multiprocessing.Process(target=view_var, args=(process_name, obj))
process_list.append(tmp_process)
# 创建进程2, 用于模拟一个进程修改类对象
process_name = "process 2"
tmp_process = multiprocessing.Process(target=modify_var, args=(process_name, obj))
process_list.append(tmp_process)
# 启动所有进程
for process in process_list:
process.start()
time.sleep(5) # 此处第一个进程start后等待5s是为了演示当前类成员变量的值。第二次循环再等待5s是为了演示子进程修改类成员变量值。

obj.set_test_list("main process", "main") # 此处演示主进程修改共享的类对象成员变量的值。
time.sleep(5) # 等待5s用于给view_var方法打印的时间

for process in process_list:
process.join()


if __name__ == "__main__":
main_process()

运行效果:

Tips:创建进程的时候可以采用
multiprocessing.Process()
的形式创建,同样也适用于进程池的形式,利用
mult_pool = multiprocessing.Pool()
mult_pool.apply_async() 创建。

参考文章