我们在进行Python多线程开发的时候经常会使用到变量,但全局变量的变化影响到每一个线程,而局部变量使用起来又非常麻烦,所以我们需要使用到ThreadLocal变量,下面小千就来给大家介绍这个ThreadLocal变量到底是什么怎么用?

      ThreadLocal变量它本身是一个全局变量,但是每个线程却可以利用它来保存属于自己的私有数据,这些私有数据对其他线程也是不可见的。下图给出了线程中这几种变量的存在情况

      全局 VS 局部变量

      首先借助一个小程序来看看多线程环境下全局变量的同步问题。

      这里我们创建了10个线程,每个线程均对全局变量 global_num 进行1000次的加1操作(循环1000次加1是为了延长单个线程执行时间,使线程执行时被中断切换),当10个线程执行完毕时,全局变量的值是多少呢?

      答案是不确定,简单来说是因为 global_num += 1 并不是一个原子操作,因此执行过程可能被其他线程中断,导致其他线程读到一个脏值。以两个线程执行 +1 为例,其中一个可能的执行序列如下(此情况下最后结果为1)

      多线程中使用全局变量时普遍存在这个问题,解决办法也很简单,可以使用互斥锁、条件变量或者是读写锁。下面考虑用互斥锁来解决上面代码的问题,只需要在进行 +1 运算前加锁,运算完毕释放锁即可,这样就可以保证运算的原子性。

      在线程中使用局部变量则不存在这个问题,因为每个线程的局部变量不能被其他线程访问。下面我们用10个线程分别对各自的局部变量进行1000次加1操作,每个线程结束时打印一共执行的操作次数(每个线程均为1000)

      可以看出这里每个线程都有自己的 local_num,各个线程之间互不干涉。

      Thread-local 对象

      上面程序中我们需要给 show 函数传递 local_num 局部变量,并没有什么不妥。不过考虑在实际生产环境中,我们可能会调用很多函数,每个函数都需要很多局部变量,这时候用传递参数的方法会很不友好。

      为了解决这个问题,一个直观的的方法就是建立一个全局字典,保存进程 ID 到该进程局部变量的映射关系,运行中的线程可以根据自己的 ID 来获取本身拥有的数据。这样,就可以避免在函数调用中传递参数,如下示例:

      保存一个全局字典,然后将线程标识符作为key,相应线程的局部数据作为 value,这种做法并不完美。

      首先,每个函数在需要线程局部数据时,都需要先取得自己的线程ID,略显繁琐。更糟糕的是,这里并没有真正做到线程之间数据的隔离,因为每个线程都可以读取到全局的字典,每个线程都可以对字典内容进行更改。

      为了更好解决这个问题,python 线程库实现了 ThreadLocal 变量(很多语言都有类似的实现,比如Java)。ThreadLocal 真正做到了线程之间的数据隔离,并且使用时不需要手动获取自己的线程 ID,如下示例

      上面示例中每个线程都可以通过 global_data.num 获得自己独有的数据,并且每个线程读取到的 global_data 都不同,真正做到线程之间的隔离。

      ThreadLocal 实现的代码量不多,但是比较难理解,涉及很多 Python 黑魔法,下篇再来分析。那么 ThreadLocal 很完美了?不!Python 的 WSGI 工具库 werkzeug 中有一个更好的 ThreadLocal 实现,甚至支持协程之间的私有数据,实现更加复杂,有机会再分析。

      本文来自千锋教育,转载请注明出处。

©著作权归作者所有:来自51CTO博客作者戏精程序媛的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 一文带你领略JS中原型链的精妙设计!
  2. 冷月手撕408之操作系统(6)-线程概述
  3. 一文学会怎样设置AppleWatch手表自动解锁iPhone手机?如何用iphone
  4. Azure首席架构师John Gossman就微软加入Linux基金会一事答疑
  5. 智能化运维时代真的来了?这些必备技术你都懂了吗?
  6. 听梅子分析测试有没有职业发展途径?
  7. zookeeper分布式锁
  8. 谷歌发布Skaffold,简化Kubernetes应用程序持续开发
  9. 2018年5大微服务发展趋势

随机推荐

  1. 在phpword中如何在表格中新建行?
  2. php 写一个算法,查寻数组里第一个大于某数
  3. 插入PHP数组作为MYSQL列
  4. PHP+Mysql 实现留言板
  5. PHP结束后执行函数
  6. 怎么使用PHPMailer实现邮件的发送??
  7. 支付宝手机接口,服务端PHP验证失败,求助
  8. 如何检查电子邮件id是否存在?
  9. 重燃你的PHP安全之火
  10. php函数 什么时候使用fflush函数