Python 本地线程对象threading.local类

在使用threading.local()之前,先了解一下局部变量和全局变量。

局部变量:

import threading
import time
 
def worker():
    x = 0
    for i in range(100):
        time.sleep(0.0001)
        x += 1
    print(threading.current_thread(),x)
 
for i in range(10):
    threading.Thread(target=worker).start()
 
运行结果:
 100
 100
 100
 100
 100
 100
 100
 100
 100
 100

上面例子使用多线程,每个子线程完成不同的计算任务,x是局部变量。

每个子线程都要压栈,每个栈是独立的空间。每次压栈,局部变量x的作用域地址是不同的(线程独享),计算结果互不干扰。

全局变量:

使用global:

import threading
import time
 
x = 0
def worker():
    global x
    x = 0
    for i in range(100):
        time.sleep(0.0001)
        x += 1
    print(threading.current_thread(),x)
 
for i in range(10):
    threading.Thread(target=worker).start()
 
运行结果:
 888
 908
 930
 937
 941
 947
 949
 955
 962
 964

上面例子中当主线程中x是全局变量时,就变成了公共资源(也就是同一个对象),每个子线程互相干扰,最终导致错误的计算结果。

Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。

使用threading.local() :

import threading
import time
 
# class A:
#     def __init__(self,x):
#         self.x = x
# a = A(0)
 
a = threading.local()#全局对象
 
def worker():
    a.x = 0
    for i in range(100):
        time.sleep(0.0001)
        a.x += 1
    print(threading.current_thread(),a.x)
 
for i in range(10):
    threading.Thread(target=worker).start()
 
运行结果:
 100
 100
 100
 100
 100
 100
 100
 100
 100
 100

每个子线程使用全局对象a,但每个线程定义的属性a.x是该线程独有的。

举一个错误的例子:,主线程中使用threading.local定义本地变量x,x在主线程中是独有的,子线程中就访问不到主线程的x的属性。

import threading
 
X='abc'
ctx=threading.local()
ctx.x=123 #主线程中定义x本地属性
print(ctx,type(ctx),ctx.x)
 
def work():
    print(X)
    print(ctx)
    print(ctx.x) #子线程访问不到
    print('Good job')
 
threading.Thread(target=work).start()
运行结果:
<_thread._local object at 0x10407bd00>  123
abc
<_thread._local object at 0x10407bd00>
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/Users/ihoney/Python/test_4.py", line 12, in work
    print(ctx.x)
AttributeError: '_thread._local' object has no attribute 'x'

ctx全局对象对主线程和子线程都是可以使用的,主线程定义了属性x,但子线程在尝试访问属性x时,就相当于访问自己线程内的属性x,而自己线程并没有定义,就会抛出AttributeError异常:'_thread._local' object has no attribute 'x'

你可能感兴趣的:(Python 本地线程对象threading.local类)