浅析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的pandas框架操作Excel文件中的数据教程
Mar 31 Python
以windows service方式运行Python程序的方法
Jun 03 Python
Python的Django框架下管理站点的基本方法
Jul 17 Python
python嵌套函数使用外部函数变量的方法(Python2和Python3)
Jan 31 Python
python内存监控工具memory_profiler和guppy的用法详解
Jul 29 Python
python PIL/cv2/base64相互转换实例
Jan 09 Python
Python3实现个位数字和十位数字对调, 其乘积不变
May 03 Python
tensorflow使用CNN分析mnist手写体数字数据集
Jun 17 Python
python 操作excel表格的方法
Dec 05 Python
PyTorch的Debug指南
May 07 Python
Python Pandas解析读写 CSV 文件
Apr 11 Python
使用Python获取字典键对应值的方法
Apr 26 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
在VS2008中编译MYSQL5.1.48的方法
2010/07/03 PHP
php中导出数据到excel时数字变为科学计数的解决方法
2013/02/03 PHP
完美解决phpdoc导出文档中@package的warning及Error的错误
2016/05/17 PHP
PHP中静态变量的使用方法实例分析
2016/12/01 PHP
laravel 5.3中自定义加密服务的方案详解
2017/05/09 PHP
PHP实现的简单适配器模式示例
2017/06/22 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
PHP使用Http Post请求发送Json对象数据代码解析
2020/07/16 PHP
如何在Mozilla Gecko 用Javascript加载XSL
2007/01/09 Javascript
jquery提升性能最佳实践小结
2010/12/06 Javascript
在JavaScript中监听IME键盘输入事件
2011/05/29 Javascript
新浪微博字数统计 textarea字数统计实现代码
2011/08/28 Javascript
日历查询的算法 如何计算某一天是星期几
2012/12/12 Javascript
asp.net中System.Timers.Timer的使用方法
2013/03/20 Javascript
js中创建对象的几种方式示例介绍
2014/01/26 Javascript
nodejs实现黑名单中间件设计
2014/06/17 NodeJs
React Native实现简单的登录功能(推荐)
2016/09/19 Javascript
微信小程序 教程之列表渲染
2016/10/18 Javascript
获取JavaScript异步函数的返回值
2016/12/21 Javascript
layui实现显示数据表格、搜索和修改功能示例
2020/06/03 Javascript
python实现比较两段文本不同之处的方法
2015/05/30 Python
Python中的descriptor描述器简明使用指南
2016/06/02 Python
Python原始字符串与Unicode字符串操作符用法实例分析
2017/07/22 Python
Python查找两个有序列表中位数的方法【基于归并算法】
2018/04/20 Python
python中join()方法介绍
2018/10/11 Python
深入了解和应用Python 装饰器 @decorator
2019/04/02 Python
Python 实现OpenCV格式和PIL.Image格式互转
2020/01/09 Python
Python 实现 T00ls 自动签到脚本代码(邮件+钉钉通知)
2020/07/06 Python
django template实现定义临时变量,自定义赋值、自增实例
2020/07/12 Python
专业销售业务员求职信
2013/11/18 职场文书
村委会贫困证明
2014/01/14 职场文书
高中英语教学反思
2014/02/04 职场文书
夫妻双方自愿离婚协议书
2014/10/24 职场文书
会计求职自荐信范文
2015/03/04 职场文书
2015年业务工作总结范文
2015/04/10 职场文书
使用opencv-python如何打开USB或者笔记本前置摄像头
2022/06/21 Python