浅析Python多线程下的变量问题


Posted in Python onApril 28, 2015

在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程,而全局变量的修改必须加锁。

但是局部变量也有问题,就是在函数调用的时候,传递起来很麻烦:

def process_student(name):
  std = Student(name)
  # std是局部变量,但是每个函数都要用它,因此必须传进去:
  do_task_1(std)
  do_task_2(std)

def do_task_1(std):
  do_subtask_1(std)
  do_subtask_2(std)

def do_task_2(std):
  do_subtask_2(std)
  do_subtask_2(std)

每个函数一层一层调用都这么传参数那还得了?用全局变量?也不行,因为每个线程处理不同的Student对象,不能共享。

如果用一个全局dict存放所有的Student对象,然后以thread自身作为key获得线程对应的Student对象如何?

global_dict = {}

def std_thread(name):
  std = Student(name)
  # 把std放到全局变量global_dict中:
  global_dict[threading.current_thread()] = std
  do_task_1()
  do_task_2()

def do_task_1():
  # 不传入std,而是根据当前线程查找:
  std = global_dict[threading.current_thread()]
  ...

def do_task_2():
  # 任何函数都可以查找出当前线程的std变量:
  std = global_dict[threading.current_thread()]
  ...

这种方式理论上是可行的,它最大的优点是消除了std对象在每层函数中的传递问题,但是,每个函数获取std的代码有点丑。

有没有更简单的方式?

ThreadLocal应运而生,不用查找dict,ThreadLocal帮你自动做这件事:

import threading

# 创建全局ThreadLocal对象:
local_school = threading.local()

def process_student():
  print 'Hello, %s (in %s)' % (local_school.student, threading.current_thread().name)

def process_thread(name):
  # 绑定ThreadLocal的student:
  local_school.student = name
  process_student()

t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()

执行结果:

Hello, Alice (in Thread-A)
Hello, Bob (in Thread-B)

全局变量local_school就是一个ThreadLocal对象,每个Thread对它都可以读写student属性,但互不影响。你可以把local_school看成全局变量,但每个属性如local_school.student都是线程的局部变量,可以任意读写而互不干扰,也不用管理锁的问题,ThreadLocal内部会处理。

可以理解为全局变量local_school是一个dict,不但可以用local_school.student,还可以绑定其他变量,如local_school.teacher等等。

ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。

Python 相关文章推荐
对Python中gensim库word2vec的使用详解
May 08 Python
Python 爬取携程所有机票的实例代码
Jun 11 Python
python opencv读mp4视频的实例
Dec 07 Python
python矩阵的转置和逆转实例
Dec 12 Python
基于python历史天气采集的分析
Feb 14 Python
Python容器使用的5个技巧和2个误区总结
Sep 26 Python
Python3使用腾讯云文字识别(腾讯OCR)提取图片中的文字内容实例详解
Feb 18 Python
python如何写try语句
Jul 14 Python
python3代码输出嵌套式对象实例详解
Dec 03 Python
详解Django关于StreamingHttpResponse与FileResponse文件下载的最优方法
Jan 07 Python
Python中使用Opencv开发停车位计数器功能
Apr 04 Python
python实现手机推送 代码也就10行左右
Apr 12 Python
python实现向ppt文件里插入新幻灯片页面的方法
Apr 28 #Python
Python实现对PPT文件进行截图操作的方法
Apr 28 #Python
在Python下尝试多线程编程
Apr 28 #Python
Python输出PowerPoint(ppt)文件中全部文字信息的方法
Apr 28 #Python
python使用append合并两个数组的方法
Apr 28 #Python
python实现的简单文本类游戏实例
Apr 28 #Python
初步解析Python下的多进程编程
Apr 28 #Python
You might like
PHP获取MSN好友列表类的实现代码
2013/06/23 PHP
php不写闭合标签的好处
2014/03/04 PHP
mac下Apache + MySql + PHP搭建网站开发环境
2014/06/02 PHP
PHP清除数组中所有字符串两端空格的方法
2014/10/20 PHP
Yii2实现ajax上传图片插件用法
2016/04/28 PHP
微信公众号开发之通过接口删除菜单
2017/02/20 PHP
PHP面向对象中new self()与 new static()的区别浅析
2017/08/17 PHP
laravel 框架实现无限级分类的方法示例
2019/10/31 PHP
php实现简单四则运算器
2020/11/29 PHP
JavaScript开发时的五个注意事项
2007/12/08 Javascript
jquery 双色表格实现代码
2009/12/08 Javascript
对象转换为原始值的实现方法
2016/06/06 Javascript
什么是JavaScript注入攻击?
2016/09/14 Javascript
JS限定手机版中图片大小随分辨率自动调整的方法
2016/12/05 Javascript
node文件批量重命名的方法示例
2017/10/23 Javascript
微信小程序上传图片功能(附后端代码)
2020/06/19 Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
2018/12/03 Javascript
vue滚动tab跟随切换效果
2020/06/29 Javascript
JavaScript之scrollTop、scrollHeight、offsetTop、offsetHeight等属性学习笔记
2020/07/15 Javascript
结合Python的SimpleHTTPServer源码来解析socket通信
2016/06/27 Python
python利用smtplib实现QQ邮箱发送邮件
2020/05/20 Python
python 中字典嵌套列表的方法
2018/07/03 Python
python3.7.0的安装步骤
2018/08/27 Python
Python实现的特征提取操作示例
2018/12/03 Python
python实现图片上添加图片
2019/11/26 Python
pytorch三层全连接层实现手写字母识别方式
2020/01/14 Python
python由已知数组快速生成新数组的方法
2020/04/08 Python
美国从事品牌鞋类零售的连锁店:Famous Footwear
2016/08/25 全球购物
Booking.com荷兰:全球酒店网上预订
2017/08/22 全球购物
美国高级音响品牌:Master&Dynamic
2018/07/05 全球购物
应届毕业生的自我鉴定
2013/11/13 职场文书
物业保安主管岗位职责
2013/12/25 职场文书
宗教学大学生职业生涯规划范文
2014/02/08 职场文书
师范生见习报告
2014/10/31 职场文书
2015年保险公司工作总结
2015/04/24 职场文书
创业计划书之闲置物品置换中心
2019/12/25 职场文书