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网络编程之UDP通信实例(含服务器端、客户端、UDP广播例子)
Apr 25 Python
Python使用MD5加密字符串示例
Aug 22 Python
在Python中处理XML的教程
Apr 29 Python
使用Python压缩和解压缩zip文件的教程
May 06 Python
详解Django中的过滤器
Jul 16 Python
详解Django-auth-ldap 配置方法
Dec 10 Python
使用python批量修改文件名的方法(视频合并时)
Mar 24 Python
python实现证件照换底功能
Aug 20 Python
Django自定义模板过滤器和标签的实现方法
Aug 21 Python
Python进度条的制作代码实例
Aug 31 Python
python列表推导式操作解析
Nov 26 Python
关于python pycharm中输出的内容不全的解决办法
Jan 10 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
《忧国的莫里亚蒂》先导宣传图与STAFF公开
2020/03/04 日漫
解析curl提交GET,POST,Cookie的简单方法
2013/06/29 PHP
php实现每天自动变换随机问候语的方法
2015/05/12 PHP
基于JQuery+PHP编写砸金蛋中奖程序
2015/09/08 PHP
php_pdo 预处理语句详解
2016/11/21 PHP
详解PHP防止盗链防止迅雷下载的方法
2017/04/26 PHP
php生成复杂验证码(倾斜,正弦干扰线,黏贴,旋转)
2018/03/12 PHP
基于JQuery的一句话搞定手风琴菜单
2012/09/14 Javascript
JS实现的表格行鼠标点击高亮效果代码
2015/11/27 Javascript
基于javascript实现仿百度输入框自动匹配功能
2016/01/03 Javascript
jQuery使用正则表达式限制文本框只能输入数字
2016/06/18 Javascript
vue v-model表单控件绑定详解
2017/05/17 Javascript
2种简单的js倒计时方式
2017/10/20 Javascript
Angular实现的自定义模糊查询、排序及三角箭头标注功能示例
2017/12/28 Javascript
Vue.js实现可配置的登录表单代码详解
2018/03/29 Javascript
JavaScript设计模式之单例模式简单实例教程
2018/07/02 Javascript
NodeJs项目中关闭ESLint的方法
2018/08/09 NodeJs
jQuery实现为动态添加的元素绑定事件实例分析
2018/09/07 jQuery
详解React项目如何修改打包地址(编译输出文件地址)
2019/03/21 Javascript
简单了解微信小程序 e.target与e.currentTarget的不同
2019/09/27 Javascript
微信js-sdk 录音功能的示例代码
2019/11/01 Javascript
vue props 单项数据流实例分享
2020/02/16 Javascript
[08:08]2014DOTA2国际邀请赛中国区预选赛精彩TOPPLAY
2014/06/25 DOTA
python使用Plotly绘图工具绘制散点图、线形图
2019/04/02 Python
使用python 写一个静态服务(实战)
2019/06/28 Python
一款CSS3实现多功能下拉菜单(带分享按)的教程
2014/11/05 HTML / CSS
西班牙第一的网上药房:PromoFarma.com
2017/04/17 全球购物
英国游戏机和游戏购物网站:365games.co.uk
2018/06/18 全球购物
Smilodox官方运动服装店:从运动服到健身配件
2020/08/27 全球购物
线程的基本概念、线程的基本状态以及状态之间的关系
2012/10/26 面试题
TCP/IP的分层模型
2013/10/27 面试题
大学生应聘自荐信
2013/10/11 职场文书
党在我心中的演讲稿
2014/09/13 职场文书
村干部四风问题整改措施
2014/09/30 职场文书
乡镇防汛工作汇报
2014/10/28 职场文书
让JavaScript代码更加精简的方法技巧
2022/06/01 Javascript