ThreadLocal

ThreadLocal

十分感谢廖雪峰老师的分享 (https://www.liaoxuefeng.com/)。

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

1. 局部变量传递

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

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading


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_1(std)
    do_subtask_2(std)

每个函数一层一层调用都这么传参数肯定不行,因为每个线程处理不同的 Student 对象,不能共享。

2. 全局变量传递

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

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

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 的代码有些复杂。

3. ThreadLocal

应用 ThreadLocal,不用查找 dictThreadLocal 帮你自动做这件事。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import threading

#
local_school = threading.local()


def process_student():
    #
    std = local_school.student
    print("Hello, %s (in %s)" % (std, threading.current_thread().name))


def process_thread(name):
    #
    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()
/usr/bin/python3.5 /home/strong/workspace/sample.py
Hello, Alice (in Thread-A)
Hello, Bob (in Thread-B)

Process finished with exit code 0

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

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

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

线程执行函数需要非常长时间时,操作系统会在 t1t2 线程间不断切换,而 join() 的作用仅仅是使得在副线程还未执行结束时,主线程不得提前结束。

4. 结论

一个 ThreadLocal 变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal 解决了参数在一个线程中各个函数之间互相传递的问题。

References

use_threadlocal.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值