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,则必 ...
随机推荐
- mac上使用Sequel Pro工具SSH连接数据库
今天在使用Mac上的Sequel Pro连接线上的数据库时,一直报ssh通道连接失败.但是同样的公钥在另一台机器就可以,真是奇怪. 通过查找日志发现有一个关键字"key_load_publi ...
- open live writer安装以及代码高亮、折叠插件安装
一.目的 方便在本地写博客,不用在浏览器上写. 二.open live writer的安装 下载open live writer 这是我的 链接:https://pan.baidu.com/s/1u8 ...
- Bootstrap初始化过程源码分析--netty客户端的启动
Bootstrap初始化过程 netty的客户端引导类是Bootstrap,我们看一下spark的rpc中客户端部分对Bootstrap的初始化过程 TransportClientFactory.cr ...
- Python 字符串多替换时性能基准测试
结论 先说结果, 直接替换是最好的. replace 一层层用, 方法笨了一点, 还可以. 时间消耗: tx2 < tx3 < tx1 < tx4 t2 < t3 < t ...
- 【Thinkphp】引入第三方类库常见问题
TP3.2在添加第三方sdk的时候,文件放在ThinkPHP/Library/Org文件夹下可独立创建文件夹(官方文档有其他思路)需对文件做以下修改. 1.第一应该修改文件的名称(下载的sdk一般是 ...
- Windows实时预览markdown
1.安装Notepad++ 2.打开Notepad++菜单栏的"插件(P)",然后打开"插件管理" 3.搜索"MarkdownViewer++&quo ...
- c#执行sql超时
超时分为多种,SqlConnection有超时选项, SqlDataAdapter也有超时选项设置如下: SqlConnection:就用链接字符串给予的Timeout设置就行单位秒: SqlData ...
- druid + mysql + mybatis 批量更新报错
首先 批量更新报错 sql injection violation, multi-statement not allow 然后看了博客:https://blog.csdn.net/qq_3634595 ...
- SpringBoot整合自定义FTP文件连接池
说明:通过GenericObjectPool实现的FTP连接池,记录一下以供以后使用环境:JDK版本1.8框架 :springboot2.1文件服务器: Serv-U1.引入依赖 <!--ftp ...
- msyql常用命令
1.创建.删除数据库 create database dbname; drop database dbname; 2.选择某一个数据库 use dbname; 3.显示所有表 show tables; ...