python multiprocessing多进程变量共享与加锁的实现


Posted in Python onOctober 02, 2019

python多进程和多线程是大家会重点了解的部分,因为很多工作如果并没有前后相互依赖关系的话其实顺序并不是非常的重要,采用顺序执行的话就必定会造成无谓的等待,任凭cpu和内存白白浪费,这是我们不想看到的。

为了解决这个问题,我们就可以采用多线程或者多进程的方式,(多线程我们之后再讲),而这两者之间是有本质区别的。就内存而言,已知进程是在执行过程中有独立的内存单元的,而多个线程是共享内存的,这是多进程和多线程的一大区别。

利用Value在不同进程中同步变量

在多进程中,由于进程之间内存相互是隔离的,所以无法在多个进程中用直接读取的方式共享变量,这时候就可以用multiprocessing库中的 Value在各自隔离的进程中共享变量。

下面是一个多进程的例子:

假设有一个counter用来记录程序经过的总循环次数,每调用一次count函数之后counter就会增加20,在主程序中用循环开10个进程分别调用count函数,那么理想状态下,在十个进程中共享的counter值到程序结束后应该是200。

from multiprocessing import Process, Value
import time

def count(v):
  for i in range(20):
    time.sleep(0.01)
    v.value += 1

def main():
  value = Value('i',0)
  processes = [Process(target=count, args=(value,)) for i in range(10)]

  for p in processes:
    p.start()
  for p in processes:
    p.join()

  print(value.value)

if __name__ == '__main__':

  for i in range(10):
    main()

运行这个例子,会得到怎样的结果呢?

188
180
168
186
183
179
186
181
166
186

我在主程序里运行了十次这个程序,而最后的结果是160-180之间,总之,没有一次到200。这是什么原因呢?

相信很多人都已经明白了问题所在,那就是因为在multiprocessing库中的Value是细粒度的,Value中有一个ctypes类型的对象,拥有一个value属性来表征内存中实际的对象。Value可以保证同时只有一个单独的线程或进程在读或者写value值。这么看起来没有什么问题。

然而在第一个进程加载value值的时候,程序却不能阻止第二个进程加载旧的值。两个进程都会把value拷贝到自己的私有内存然后进行处理,并写回到共享值里。

那么这么会出现什么问题呢?

最后的共享值只接收到了一次值的增加,而非两次。

利用Lock在不同进程共享变量时加锁

上面的问题其实可以用一个非常简单的方法解决,我们只需要调用multiprocessing库中的Lock (锁)就可以保证一次只能有一个进程访问这个共享变量。修改后的代码如下:

from multiprocessing import Process, Value, Lock
from time import sleep

def count(x,lock):
  for i in range(20):
    sleep(0.01)
    with lock:
      x.value += 1


def main():
  counter = Value('i',0)
  lock = Lock()
  processes = [Process(target=count,args=(counter,lock)) for i in range(10)]
  for p in processes:
    p.start()
  for p in processes:
    p.join()

  print(counter.value)

if __name__ == '__main__':
  for i in range(10):
    main()

这样一来,输出的结果就会恒定为200了。

一些补充

1. 调用get_lock() 函数

其实Value这个包里已经包含了锁的概念,如果调用get_lock() 函数就可以自动给共享变量加锁。这样其实是比较推荐的方式,因为这样就不需要同时调用两个包。修改如下:

from multiprocessing import Process, Value
from time import sleep

def count(x):
  for i in range(20):
    global counter # 声明全局变量
    sleep(0.01)
    with counter.get_lock(): # 直接调用get_lock()函数获取锁
      x.value += 1

def main():
  processes = [Process(target=count, args=(counter,)) for i in range(10)]
  for p in processes:
    p.start()
  for p in processes:
    p.join()

  print(counter.value)

if __name__ == '__main__':
  counter = Value('i', 0) # 需要把全局变量移到主程序
  main()

上面的程序更加明确,且最终结果也是200。

2. 使用 multiprocessing.RawValue

整个multiprocessing包里刚刚调用的Value和Lock还可以统一被 multiprocessing.RawValue取代。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用python实现的可以拷贝或剪切一个文件列表中的所有文件
Apr 30 Python
在Python中使用pngquant压缩png图片的教程
Apr 09 Python
Python下线程之间的共享和释放示例
May 04 Python
python 时间戳与格式化时间的转化实现代码
Mar 23 Python
Python实现定时精度可调节的定时器
Apr 15 Python
详谈Python3 操作系统与路径 模块(os / os.path / pathlib)
Apr 26 Python
Python 创建空的list,以及append用法讲解
May 04 Python
Python网络爬虫之爬取微博热搜
Apr 18 Python
如何利用pygame实现简单的五子棋游戏
Dec 29 Python
基于Python绘制美观动态圆环图、饼图
Jun 03 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
Aug 03 Python
Python 实现绘制子图及子图刻度的变换等问题
May 31 Python
Python shutil模块用法实例分析
Oct 02 #Python
Windows平台Python编程必会模块之pywin32介绍
Oct 01 #Python
Python全栈之列表数据类型详解
Oct 01 #Python
python2和python3应该学哪个(python3.6与python3.7的选择)
Oct 01 #Python
使用Python制作一个打字训练小工具
Oct 01 #Python
Python + Flask 实现简单的验证码系统
Oct 01 #Python
python 矢量数据转栅格数据代码实例
Sep 30 #Python
You might like
PHP实现多条件查询实例代码
2010/07/17 PHP
《PHP编程最快明白》第四讲:日期、表单接收、session、cookie
2010/11/01 PHP
php环境无法上传文件的解决方法
2014/04/30 PHP
destoon公司主页模板风格的添加方法
2014/06/20 PHP
php将字符串随机分割成不同长度数组的方法
2015/06/01 PHP
PHP利用APC模块实现大文件上传进度条的方法
2015/10/29 PHP
JS实现定时自动关闭DIV层提示框的方法
2015/05/11 Javascript
Web开发中客户端的跳转与服务器端的跳转的区别
2017/03/05 Javascript
Javascript实现时间倒计时效果
2017/07/15 Javascript
通过webpack引入第三方库的方法
2018/07/20 Javascript
详解使用Nuxt.js快速搭建服务端渲染(SSR)应用
2019/03/13 Javascript
详解vue 不同环境配置不同的打包命令
2019/04/07 Javascript
详解jQuery如何实现模糊搜索
2019/05/10 jQuery
基于javascript的无缝滚动动画1
2020/08/07 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
2020/08/14 Javascript
Python更新数据库脚本两种方法及对比介绍
2017/07/27 Python
python3利用tcp实现文件夹远程传输
2018/07/28 Python
Python OpenCV图像指定区域裁剪的实现
2019/10/30 Python
python正则表达式匹配IP代码实例
2019/12/28 Python
为什么黑客都用python(123个黑客必备的Python工具)
2020/01/31 Python
Python创建空列表的字典2种方法详解
2020/02/13 Python
利用CSS3的特性改变文本选中时的颜色
2013/09/11 HTML / CSS
纯css3实现走马灯效果
2014/12/26 HTML / CSS
西班牙网上书店:Casa del Libro
2016/11/01 全球购物
丝芙兰加拿大官方网站:SEPHORA加拿大
2018/11/20 全球购物
COS美国官网:知名服装品牌
2019/04/08 全球购物
酒店服务与管理毕业生求职信
2013/11/02 职场文书
《在大海中永生》教学反思
2014/02/24 职场文书
优秀纪检干部材料
2014/08/27 职场文书
2015年简历自我评价范文
2015/03/11 职场文书
外贸英文求职信范文
2015/03/19 职场文书
2015学习委员工作总结范文
2015/04/03 职场文书
vue使用节流函数的踩坑实例指南
2021/05/20 Vue.js
pytorch交叉熵损失函数的weight参数的使用
2021/05/24 Python
javascript的var与let,const之间的区别详解
2022/02/18 Javascript
Go语言编译原理之变量捕获
2022/08/05 Golang