Python3多进程共享变量实现方法

今天同事反映一个问题让帮忙看一下:多进程共用一个变量,在一个进程中修改后,在另外的进程中并没有产生修改。

 

一、错误的实现方式

最初以为是没添加global声明导致修改未生效,但实际操作发现global方式在多进程中也只能读不能写。错误示例代码如下:

复制代码
import multiprocessing

# 声明一个全局变量 share_var = ["start flag"]
def sub_process(process_name): # 企图像单个进程那样通过global声明使用全局变量 global share_var share_var.append(process_name) # 但是很可惜,在多进程中这样引用只能读,修改其他进程不会同步改变 for item in share_var: print(f"{process_name}-{item}") pass
def main_process(): process_list = [] # 创建进程1 process_name = "process 1" tmp_process = multiprocessing.Process(target=sub_process,args=(process_name,)) process_list.append(tmp_process) # 创建进程2 process_name = "process 2" tmp_process = multiprocessing.Process(target=sub_process, args=(process_name,)) process_list.append(tmp_process) # 启动所有进程 for process in process_list: process.start() for process in process_list: process.join()
if __name__ == "__main__": main_process()
复制代码

执行结果如下,可以看到进程1中的修改未表现在进程2中(不过要注意,和多线程一样,如果运算量再大一点进程1并不一定比进程2先执行):

 

二、共享普通类型变量实现方法

参考:https://blog.csdn.net/houyanhua1/article/details/78244288

复制代码
import multiprocessing

# 不能将共享变量和共享锁定义成全局变量然后通过global引用那样会报错,只能传过来 def sub_process(process_name,share_var,share_lock): # 获取锁 share_lock.acquire() share_var.append(process_name) # 释放锁 share_lock.release() for item in share_var: print(f"{process_name}-{item}") pass
def main_process(): # 单个值声明方式。typecode是进制类型,C写法和Python写法都可以,见下方表格;value是初始值。 # 这种单值形式取值赋值需要通过get()/set()方法进行,不能直接如一般变量那样取值赋值 # share_var = multiprocessing.Manager().Value(typecode, value) # 数组声明方式。typecode是数组变量中的变量类型,sequence是数组初始值 # share_var = multiprocessing.Manager().Array(typecode, sequence) # 字典声明方式 # share_var = multiprocessing.Manager().dict() # 列表声明方式 share_var = multiprocessing.Manager().list() share_var.append("start flag") # 声明一个进程级共享锁 # 不要给多进程传threading.Lock()或者queue.Queue()等使用线程锁的变量,得用其进程级相对应的类 # 不然会报如“TypeError: can't pickle _thread.lock objects”之类的报错 share_lock = multiprocessing.Manager().Lock() process_list = []
process_name = "process 1" tmp_process = multiprocessing.Process(target=sub_process,args=(process_name,share_var,share_lock)) process_list.append(tmp_process)
process_name = "process 2" tmp_process = multiprocessing.Process(target=sub_process, args=(process_name,share_var,share_lock)) process_list.append(tmp_process)
for process in process_list: process.start()
for process in process_list: process.join()
if __name__ == "__main__": main_process()
复制代码

执行结果如下,可以看到进程1中的修改已表现在进程2中(不过要注意,和多线程一样,如果运算量再大一点进程1并不一定比进程2先执行):

typecode如果是数值或单个字符,可为以下类型(注意有引号):

Type CodeC TypePython Type
'c'charcharacter
'b'signed charint
'B'unsigned charint
'u'Py_UNICODEunicode character
'h'signed shortint
'H'unsigned shortint
'i'signed intint
'I'unsigned intint
'l'signed longint
'L'unsigned longint
'f'floatfloat
'd'doublefloat

 

如果是字符串类型,typecode可为以下第一列形式(注意无引号):

ctypes typeC typePython type

c_bool

_Boolbool (1)
char char1-character string
c_wcharwchar_t1-character unicode string
c_bytecharint/long
c_ubyteunsigned charint/long
c_shortshortint/long
c_ushortunsigned shortint/long
c_intintint/long
c_uintunsigned inint/long
c_longlongint/long
c_ulongunsigned longint/long
c_longlong__int64 or long longint/long
c_ulonglongunsigned __int64 or unsigned long longint/long
c_floatfloatfloat
c_doubledoublefloat
c_longdoublelong doublefloat
c_char_pchar * (NUL terminated)string or None

c_wchar_p

wchar_t * (NUL terminated)unicode or None
c_void_pvoid *int/long or None

 


三、共享实例化对象实现方法

同事还想共享一个文件对象,然后问上边的方法是不是只能共享字典、列表,没法共享对象。

回头一看,Value和Array中typecode要求是c语言中存在的类型,其他只有dict()和list()方法没有其他方法,所以似乎上边的方法共享实例化对象是不行的。

 

3.1 共享不需要修改实例化对象实现方法----使用global

但我们前面说过global方式不可以修改,但读还是没问题的;所以对象引用还是可以使用global方式。

复制代码
import multiprocessing
import threading

# 实例化一个全局文件对象 file_obj = open("1.txt","a") share_lock = threading.Lock()
def sub_process(process_name): global file_obj,share_lock share_lock.acquire() file_obj.writelines(f"{process_name}") share_lock.release() pass
def main_process(): process_list = [] # 创建进程1 process_name = "process 1" tmp_process = multiprocessing.Process(target=sub_process,args=(process_name,)) process_list.append(tmp_process) # 创建进程2 process_name = "process 2" tmp_process = multiprocessing.Process(target=sub_process, args=(process_name,)) process_list.append(tmp_process) # 启动所有进程 for process in process_list: process.start() for process in process_list: process.join()
if __name__ == "__main__": main_process()
复制代码

 

3.2 共享需要修改实例化对象实现方法----使用BaseManager

global方式不能修改变量(如要修改其成员变量),在大多时候也是可以了,但总让人觉得不是一种完美的实现方法。有没有可以修改的实现方法呢,答案是有的,可以使用BaseManager。示例代码如下。

参考:https://blog.csdn.net/jacke121/article/details/82658471

复制代码
import multiprocessing
from multiprocessing.managers import BaseManager
import threading

# 锁可以通过global也可以在Process中传无所谓 share_lock = threading.Lock() # 定义一个要共享实例化对象的类
class Test(): def __init__(self): self.test_list = ["start flag"] def test_function(self,arg): self.test_list.append(arg) def print_test_list(self): for item in self.test_list: print(f"{item}")
def sub_process(process_name,obj): global share_lock share_lock.acquire() obj.test_function(f"{process_name}") share_lock.release() obj.print_test_list() pass
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) manager.start() obj = manager.Test() process_list = [] # 创建进程1 process_name = "process 1" tmp_process = multiprocessing.Process(target=sub_process,args=(process_name,obj)) process_list.append(tmp_process) # 创建进程2 process_name = "process 2" tmp_process = multiprocessing.Process(target=sub_process, args=(process_name,obj)) process_list.append(tmp_process) # 启动所有进程 for process in process_list: process.start() for process in process_list: process.join()
if __name__ == "__main__": main_process()
复制代码

执行结果如下,可以看到进程1中的修改已表现在进程2中(不过要注意,和多线程一样,如果运算量再大一点进程1并不一定比进程2先执行):

 

参考:

https://blog.51cto.com/11026142/1874807

https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值