最近遇到了一个非常麻烦的问题: 复杂的讲, 由于对grpc的了解仅是皮毛, 导致grpc的服务端收到数据后, 没有办法直接使用这些数据, 因为项目中运行grpc服务端被本人封到了一个类一个子进程中, 如下图所示, 本来希望定义一个全局变量global, 然后通过grpc服务端得到数据, 在从主函数中(父进程)中使用这个全局变量的数据, 但是无论进行怎样的尝试都无法实现, 调试了一天, 总觉得是我的语法或者代码逻辑有问题, 直到我查看了一个博客, 写明了一句话 创建进程的时候, 会把资源和全局变量统统拷贝一波, 不会跟父进程共享变量 我傻了呀我, 根据这个线索, 我继续捋顺了一下, 终于查到了需要怎么解决, 那就是下文提到的 from multiprocessing import Manager
简答来讲:
- 创建进程, 不管全局还是局部变量, 子进程都统统深拷贝了一份
- 想要进程间共享参数, 可以使用
from multiprocessing import Process, Manager - 下面给出实验以及使用
献上我之前写的python的进程和线程
实验1 普通的全局变量在进程间不可用
import numpy as np
import random
import time
from multiprocessing import Process, Manager
tvm_data = {}
tvm_data["action"] = 0
def subprocess1():
global tvm_data
while True:
for _ in range(1000):
print("fun action = ",tvm_data["action"])
tvm_data["action"] = _
time.sleep(1)
def main():
global tvm_data
p1 = Process(target=subprocess1, args=())
p1.start()
while True:
tvm_data["action"] = 0
print("main action = ",tvm_data["action"])
time.sleep(2)
main()
'''
main action = 0
fun action = 0
fun action = 0
main action = 0
fun action = 1
fun action = 2
main action = 0
fun action = 3
fun action = 4
main action = 0
fun action = 5
fun action = 6
main action = 0
fun action = 7
'''
实验2 使用Manger创建的字典, 在子进程中调用, 有效
import numpy as np
import random
import time
from multiprocessing import Process, Manager
mdata = Manager().dict()
mdata["action"] = 0
tvm_data = {}
tvm_data["action"] = 0
def subprocess1():
global tvm_data
while True:
for _ in range(1000):
print("fun action = ",tvm_data["action"])
tvm_data["action"] = _
time.sleep(1)
def subprocess2():
while True:
for _ in range(1000):
print("fun action = ",mdata["action"])
mdata["action"] += 1
time.sleep(0.5)
def main():
global tvm_data
p1 = Process(target=subprocess2, args=())
p1.start()
while True:
print("main action = ",mdata["action"])
mdata["action"] = 0
time.sleep(2)
main()
'''
main action = 0
fun action = 0
fun action = 1
fun action = 2
fun action = 3
main action = 4
fun action = 0
fun action = 1
fun action = 2
fun action = 3
main action = 4
fun action = 0
fun action = 1
fun action = 2
fun action = 3
main action = 4
fun action = 0
fun action = 1
fun action = 2
fun action = 3
main action = 4
fun action = 0
fun action = 1
'''
总结
Manager支持的类型有
list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array
但当使用Manager 处理list、dict 等可变数据类型时,需要注意一个陷阱,即Manager 对象无法监测到它引用的可变对象值的修改,需要通过触发__setitem__ 方法来让它获得通知。
而触发__setitem__ 方法比较直接的办法就是增加一个中间变量,如同在C语言中交换两个变量的值一样:
int a=1, b=2;
int tmp=a;
a=b;
b=tmp;
所以如果想要进程间使用全局变量, 只需要利用manager 定义变量即可
如果这篇文章对你有所收获, 请点赞关注, 感谢支持
|