探究Python多进程编程下线程之间变量的共享问题


Posted in Python onMay 05, 2015

 1、问题:

群中有同学贴了如下一段代码,问为何 list 最后打印的是空值?
 

from multiprocessing import Process, Manager
import os
 
manager = Manager()
vip_list = []
#vip_list = manager.list()
 
def testFunc(cc):
  vip_list.append(cc)
  print 'process id:', os.getpid()
 
if __name__ == '__main__':
  threads = []
 
  for ll in range(10):
    t = Process(target=testFunc, args=(ll,))
    t.daemon = True
    threads.append(t)
 
  for i in range(len(threads)):
    threads[i].start()
 
  for j in range(len(threads)):
    threads[j].join()
 
  print "------------------------"
  print 'process id:', os.getpid()
  print vip_list

其实如果你了解 python 的多线程模型,GIL 问题,然后了解多线程、多进程原理,上述问题不难回答,不过如果你不知道也没关系,跑一下上面的代码你就知道是什么问题了。
 

python aa.py
process id: 632
process id: 635
process id: 637
process id: 633
process id: 636
process id: 634
process id: 639
process id: 638
process id: 641
process id: 640
------------------------
process id: 619
[]

将第 6 行注释开启,你会看到如下结果:
 

process id: 32074
process id: 32073
process id: 32072
process id: 32078
process id: 32076
process id: 32071
process id: 32077
process id: 32079
process id: 32075
process id: 32080
------------------------
process id: 32066
[3, 2, 1, 7, 5, 0, 6, 8, 4, 9]

2、python 多进程共享变量的几种方式:
(1)Shared memory:
Data can be stored in a shared memory map using Value or Array. For example, the following code

http://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes
 

from multiprocessing import Process, Value, Array
 
def f(n, a):
  n.value = 3.1415927
  for i in range(len(a)):
    a[i] = -a[i]
 
if __name__ == '__main__':
  num = Value('d', 0.0)
  arr = Array('i', range(10))
 
  p = Process(target=f, args=(num, arr))
  p.start()
  p.join()
 
  print num.value
  print arr[:]

结果:
 

3.1415927
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

(2)Server process:

A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.
A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value and Array.
代码见开头的例子。

http://docs.python.org/2/library/multiprocessing.html#managers
3、多进程的问题远不止这么多:数据的同步

看段简单的代码:一个简单的计数器:
 

from multiprocessing import Process, Manager
import os
 
manager = Manager()
sum = manager.Value('tmp', 0)
 
def testFunc(cc):
  sum.value += cc
 
if __name__ == '__main__':
  threads = []
 
  for ll in range(100):
    t = Process(target=testFunc, args=(1,))
    t.daemon = True
    threads.append(t)
 
  for i in range(len(threads)):
    threads[i].start()
 
  for j in range(len(threads)):
    threads[j].join()
 
  print "------------------------"
  print 'process id:', os.getpid()
  print sum.value

结果:
 

------------------------
process id: 17378
97

也许你会问:WTF?其实这个问题在多线程时代就存在了,只是在多进程时代又杯具重演了而已:Lock!
 

from multiprocessing import Process, Manager, Lock
import os
 
lock = Lock()
manager = Manager()
sum = manager.Value('tmp', 0)
 
 
def testFunc(cc, lock):
  with lock:
    sum.value += cc
 
 
if __name__ == '__main__':
  threads = []
 
  for ll in range(100):
    t = Process(target=testFunc, args=(1, lock))
    t.daemon = True
    threads.append(t)
 
  for i in range(len(threads)):
    threads[i].start()
 
  for j in range(len(threads)):
    threads[j].join()
 
  print "------------------------"
  print 'process id:', os.getpid()
  print sum.value

这段代码性能如何呢?跑跑看,或者加大循环次数试一下。。。
4、最后的建议:

    Note that usually sharing data between processes may not be the best choice, because of all the synchronization issues; an approach involving actors exchanging messages is usually seen as a better choice. See also Python documentation: As mentioned above, when doing concurrent programming it is usually best to avoid using shared state as far as possible. This is particularly true when using multiple processes. However, if you really do need to use some shared data then multiprocessing provides a couple of ways of doing so.

5、Refer:

http://stackoverflow.com/questions/14124588/python-multiprocessing-shared-memory

http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing/

http://docs.python.org/2/library/multiprocessing.html#multiprocessing.sharedctypes.synchronized

Python 相关文章推荐
python抓取网页中的图片示例
Feb 28 Python
Python中的Numeric包和Numarray包使用教程
Apr 13 Python
在windows下快速搭建web.py开发框架方法
Apr 22 Python
python实现rsa加密实例详解
Jul 19 Python
浅谈python for循环的巧妙运用(迭代、列表生成式)
Sep 26 Python
Python 快速实现CLI 应用程序的脚手架
Dec 05 Python
Python实现读取Properties配置文件的方法
Mar 29 Python
django传值给模板, 再用JS接收并进行操作的实例
May 28 Python
Python实现查询某个目录下修改时间最新的文件示例
Aug 29 Python
python安装scipy的步骤解析
Sep 28 Python
python网络编程:socketserver的基本使用方法实例分析
Apr 09 Python
在pycharm中使用matplotlib.pyplot 绘图时报错的解决
Jun 01 Python
浅谈Python中的数据类型
May 05 #Python
用Python实现一个简单的能够上传下载的HTTP服务器
May 05 #Python
使用Python程序抓取新浪在国内的所有IP的教程
May 04 #Python
Python版微信红包分配算法
May 04 #Python
用Python编写一个每天都在系统下新建一个文件夹的脚本
May 04 #Python
用Python编写生成树状结构的文件目录的脚本的教程
May 04 #Python
使用Python脚本将Bing的每日图片作为桌面的教程
May 04 #Python
You might like
php 变量引用与变量销毁机制详细介绍
2016/12/05 PHP
JavaScript Event学习第七章 事件属性
2010/02/07 Javascript
javascript在事件监听方面的兼容性小结
2010/04/07 Javascript
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
跟我学Nodejs(一)--- Node.js简介及安装开发环境
2014/05/20 NodeJs
bootstrap data与jquery .data
2014/07/07 Javascript
jquery中each方法示例和常用选择器
2014/07/08 Javascript
Javascript控制input输入时间格式的方法
2015/01/28 Javascript
原生js模拟淘宝购物车项目实战
2015/11/18 Javascript
jQuery基于muipicker实现仿ios时间选择
2016/02/22 Javascript
JQuery控制图片由中心点逐渐放大效果
2016/06/26 Javascript
canvas实现流星雨的背景效果
2017/01/13 Javascript
vue货币过滤器的实现方法
2017/04/01 Javascript
vue cli构建的项目中请求代理与项目打包问题
2018/02/26 Javascript
webpack4 升级迁移的实现
2018/09/12 Javascript
使用webpack打包后的vue项目如何正确运行(express)
2018/10/26 Javascript
JS实现提示框跟随鼠标移动
2019/08/27 Javascript
解决layui动态加载复选框无法选中的问题
2019/09/20 Javascript
微信小程序实现录制、试听、上传音频功能(带波形图)
2020/02/27 Javascript
Python常用算法学习基础教程
2017/04/13 Python
Python中生成Epoch的方法
2017/04/26 Python
Python实现按学生年龄排序的实际问题详解
2017/08/29 Python
将Django项目部署到CentOs服务器中
2018/10/18 Python
pyinstaller将含有多个py文件的python程序做成exe
2020/04/29 Python
Django REST Swagger实现指定api参数
2020/07/07 Python
python输出结果刷新及进度条的实现操作
2020/07/13 Python
CSS3实现水平居中、垂直居中、水平垂直居中的实例代码
2020/02/27 HTML / CSS
New Balance英国官方网站:始于1906年,百年慢跑品牌
2016/12/07 全球购物
加拿大最大的相机店:Henry’s
2017/05/17 全球购物
英国灯具和灯泡网上商店:Lights.co.uk
2018/02/02 全球购物
三下乡活动方案
2014/01/31 职场文书
年终晚会活动方案
2014/08/21 职场文书
2014乡镇机关党员个人对照检查材料思想汇报
2014/10/09 职场文书
2014年教学管理工作总结
2014/12/02 职场文书
勇敢的心观后感
2015/06/09 职场文书
运动会加油稿50字
2015/07/21 职场文书