浅析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编程-将Python程序转化为可执行程序[整理]
Apr 09 Python
python 读写、创建 文件的方法(必看)
Sep 12 Python
Python的语言类型(详解)
Jun 24 Python
浅谈Django自定义模板标签template_tags的用处
Dec 20 Python
Python爬虫实例_城市公交网络站点数据的爬取方法
Jan 10 Python
Python实现可设置持续运行时间、线程数及时间间隔的多线程异步post请求功能
Jan 11 Python
Python for循环生成列表的实例
Jun 15 Python
python实现电子书翻页小程序
Jul 23 Python
python 比较字典value的最大值的几种方法
Apr 17 Python
Python单元测试及unittest框架用法实例解析
Jul 09 Python
python中_del_还原数据的方法
Dec 09 Python
用基于python的appium爬取b站直播消费记录
Apr 17 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
Yii框架在页面输出执行sql语句以方便调试的实现方法
2014/12/24 PHP
一波PHP中cURL库的常见用法代码示例
2016/05/06 PHP
php mysql_list_dbs()函数用法示例
2017/03/29 PHP
showModelessDialog()使用详解
2006/09/07 Javascript
定时器(setTimeout/setInterval)调用带参函数失效解决方法
2013/03/26 Javascript
使用Plupload实现直接上传附件至七牛云存储
2014/12/26 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
2017/08/17 Javascript
微信小程序提交form操作示例
2018/12/30 Javascript
ES6 Promise对象的含义和基本用法分析
2019/06/14 Javascript
vue循环数组改变点击文字的颜色
2019/10/14 Javascript
微信小程序中的上拉、下拉菜单功能
2020/03/13 Javascript
js实现简单五子棋游戏
2020/05/28 Javascript
js操作两个json数组合并、去重,以及删除某一项元素
2020/09/22 Javascript
基于Python的身份证号码自动生成程序
2014/08/15 Python
Python函数式编程指南(二):从函数开始
2015/06/24 Python
wxpython中Textctrl回车事件无效的解决方法
2016/07/21 Python
Python做智能家居温湿度报警系统
2018/09/25 Python
django 简单实现登录验证给你
2019/11/06 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
tensorflow 查看梯度方式
2020/02/04 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
2020/03/02 Python
python线程优先级队列知识点总结
2021/02/28 Python
Kiwi.com中国:找到特价机票并发现新目的地
2019/10/27 全球购物
施华洛世奇巴西官网:SWAROVSKI巴西
2019/12/03 全球购物
联强国际笔试题面试题
2013/07/10 面试题
大堂副理的岗位职责范文
2014/02/17 职场文书
公开服务承诺制度
2014/03/26 职场文书
《小鹰学飞》教学反思
2014/04/23 职场文书
演讲比赛策划方案
2014/06/11 职场文书
白酒营销策划方案
2014/08/17 职场文书
公司副总经理岗位职责
2014/10/01 职场文书
公安交警中队队长个人对照检查材料思想汇报
2014/10/05 职场文书
龙潭大峡谷导游词
2015/02/10 职场文书
城管年度个人总结
2015/02/28 职场文书
获奖感言一句话
2015/07/31 职场文书
Python机器学习之基于Pytorch实现猫狗分类
2021/06/08 Python