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 Code | C Type | Python Type |
'c' | char | character |
'b' | signed char | int |
'B' | unsigned char | int |
'u' | Py_UNICODE | unicode character |
'h' | signed short | int |
'H' | unsigned short | int |
'i' | signed int | int |
'I' | unsigned int | int |
'l' | signed long | int |
'L' | unsigned long | int |
'f' | float | float |
'd' | double | float |
如果是字符串类型,typecode可为以下第一列形式(注意无引号):
ctypes type | C type | Python type |
c_bool |
_Bool | bool (1) |
char | char | 1-character string |
c_wchar | wchar_t | 1-character unicode string |
c_byte | char | int/long |
c_ubyte | unsigned char | int/long |
c_short | short | int/long |
c_ushort | unsigned short | int/long |
c_int | int | int/long |
c_uint | unsigned in | int/long |
c_long | long | int/long |
c_ulong | unsigned long | int/long |
c_longlong | __int64 or long long | int/long |
c_ulonglong | unsigned __int64 or unsigned long long | int/long |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char * (NUL terminated) | string or None |
c_wchar_p |
wchar_t * (NUL terminated) | unicode or None |
c_void_p | void * | 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
Python3多进程共享变量实现方法的更多相关文章
- Python3 多进程编程 - 学习笔记
Python3 多进程编程(Multiprocess programming) 为什么使用多进程 具体用法 Python多线程的通信 进程对列Queue 生产者消费者问题 JoinableQueue ...
- 【python】多进程共享变量
有一个字典变量,需要在多个进程间共享 使用Manager, 下面是一个小例子. 注意使用json前需要将类型转换. #!/usr/bin/python # coding=utf-8 import js ...
- python3打包成exe---pyinstaller方法
前言: 主要介绍python3的pyinstaller打包方法 pyinstaller安装参考地址:http://www.pyinstaller.org/ pywin32的下载地址:https://s ...
- python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法
python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...
- python2.x脚本转换为python3.x脚本的方法
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/dushu990/article/details/73549174 python2.x脚本转换为pyt ...
- Python3 多进程和多线程
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为 ...
- python多进程共享变量Value使用tips
前言: 在使用tornado的多进程时,需要多个进程共享一个状态变量,于是考虑使用multiprocessing.Value(对于该变量的具体细节请查阅相关资料).在根据网上资料使用Value时,由于 ...
- python3.x pool.map方法的实质
我使用多进程的一般方式,都是multiprocessing模块中的Pool.map()方法.下面写一个简单的示例和解析.至于此种方法使用多进程的效率问题,还希望大佬予以指正. 示例: "&q ...
- 【python】多进程共享变量Manager
Manager的复杂结构赋值问题 Manager的字典类型: 如果value是简单类型,比如int,可以直接赋值给共享变量,并可以后续直接修改 如果value是复杂类型 ,比如list,dict,则必 ...
随机推荐
- ES6 数组的拓展(五)
一.扩展运算符(...)将数组转化为以,分割的字符串eg: console.log(...[1,2,3,4]); //1 2 3 4 将字符串转化为数组eg: console.log([...'hel ...
- uni-app插件ColorUI步骤条
1. uni-app插件ColorUI步骤条 1.1. 前言 uni-app就不介绍了,前面几篇已经有所介绍,不知道的可以翻看我前面几篇博客 ColorUI-uniApp是uni-app的一款ui组件 ...
- 英语cowbezoar牛黄cowbezoar单词
牛黄(cowbezoar)是脊索动物门哺乳纲牛科动物牛胆囊的胆结石.在胆囊中产生的称“胆黄”或“蛋黄”,在胆管中产生的称“管黄”,在肝管中产生的称“肝黄”. 中文学名牛黄 拉丁学名Bos taurus ...
- 让Discuz! X3.2 SEO标题里的“-”支持空格
打开Discuz!根目录下source\class\helper\helper_seo.php文件找到如下代码: public static function strreplace_strip_spl ...
- UiPath: Send SMTP Mail Message 发送带附件的邮件
Tips:关于Hotmail的server和port的获取方式,请参考以下链接 https://support.office.com/en-us/article/Server-settings-you ...
- LeetCode 825. Friends Of Appropriate Ages
原题链接在这里:https://leetcode.com/problems/friends-of-appropriate-ages/ 题目: Some people will make friend ...
- Pandas | 03 DataFrame 数据帧
数据帧(DataFrame)是二维数据结构,即数据以行和列的表格方式排列. 数据帧(DataFrame)的功能特点: 潜在的列是不同的类型 大小可变 标记轴(行和列) 可以对行和列执行算术运算 结构体 ...
- 10-day03-注释
Python注释 msg = “我爱你中国!” #单行注释使用 ''''''多行注释使用 print(msg) #this code is for >>>> ‘’‘print( ...
- epoll及实现http多任务(python)
1.epoll用到了文件描述符的概念: 首先,操作系统中一切皆文件 文件与文件描述符fd 文件是应用程序与系统(包括特定硬件设备)之间的桥梁,而文件描述符就是应用程序使用这个"桥梁" ...
- NOIP2019翻车前写(and 抄)过的代码
咕咕咕.按上传时间升序排列. //树的重心 void dfs(int x) { v[x]=1; size[x]=1; int max_part=0; for(int i=hed[x];i;i=nxt[ ...