浅析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中set使用
Jun 30 Python
详解python 发送邮件实例代码
Dec 22 Python
python flask中静态文件的管理方法
Mar 20 Python
python 实现在txt指定行追加文本的方法
Apr 29 Python
python3处理含有中文的url方法
May 10 Python
Django项目中包含多个应用时对url的配置方法
May 30 Python
Python面向对象实现一个对象调用另一个对象操作示例
Apr 08 Python
python利用wx实现界面按钮和按钮监听和字体改变的方法
Jul 17 Python
Django中的静态文件管理过程解析
Aug 01 Python
Python3 使用pillow库生成随机验证码
Aug 26 Python
解决tensorflow由于未初始化变量而导致的错误问题
Jan 06 Python
Python docx库删除复制paragraph及行高设置图片插入示例
Jul 23 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
Apache2中实现多网站域名绑定的实现方法
2011/06/01 PHP
说说PHP的autoLoad自动加载机制
2012/09/27 PHP
PHP伪静态Rewrite设置之APACHE篇
2014/07/30 PHP
PHP四种基本排序算法示例
2015/04/09 PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
2015/11/25 PHP
Symfony2联合查询实现方法
2016/03/18 PHP
javascript中的事件代理初探
2014/03/08 Javascript
详解AngularJS中的作用域
2015/06/17 Javascript
Bootstrap每天必学之简单入门
2015/11/19 Javascript
基于JS实现Android,iOS一个手势动画效果
2016/04/27 Javascript
jQuery限制图片大小的方法
2016/05/25 Javascript
AngularJS实现数据列表的增加、删除和上移下移等功能实例
2016/09/05 Javascript
浅析Javascript的自动分号插入(ASI)机制
2016/09/29 Javascript
js实现图片加载淡入淡出效果
2017/04/07 Javascript
使用D3.js构建实时图形的示例代码
2018/08/28 Javascript
浅谈KOA2 Restful方式路由初探
2019/03/14 Javascript
小程序异步问题之多个网络请求依次执行并依次收集请求结果
2019/05/05 Javascript
[00:32]2018DOTA2亚洲邀请赛出场——VP
2018/04/04 DOTA
python实现人人网登录示例分享
2014/01/19 Python
python使用urlparse分析网址中域名的方法
2015/04/15 Python
python读取视频流提取视频帧的两种方法
2020/10/22 Python
Python3.6实现连接mysql或mariadb的方法分析
2018/05/18 Python
Python语言检测模块langid和langdetect的使用实例
2019/02/19 Python
Python使用pyautocad+openpyxl处理cad文件示例
2019/07/11 Python
python 计算方位角实例(根据两点的坐标计算)
2020/01/17 Python
pandas分组聚合详解
2020/04/10 Python
html5服务器推送_动力节点Java学院整理
2017/07/12 HTML / CSS
德国旅行、体验和活动的预订平台:Watado
2019/12/04 全球购物
就业自荐书
2013/12/05 职场文书
连带责任保证书
2014/04/29 职场文书
学校四风对照检查材料
2014/08/28 职场文书
信访维稳工作汇报
2014/10/27 职场文书
小学生五一劳动节演讲稿
2015/03/18 职场文书
道歉情书大全
2015/05/12 职场文书
python 管理系统实现mysql交互的示例代码
2021/12/06 Python
Java实现HTML转为Word的示例代码
2022/06/28 Java/Android