当我们使用线程时,如果多线程同时对一个全局变量进行修改,很容易造成错误,这是我们可以利用加锁的方式,让线程一个一个进行操作
同样我们可以threading.local来实现
threading.local的使用
不使用threading.local时
from threading import Thread
from threading import local
import time
# xianglong = local()
xianglong = -1
def task(arg):
global xianglong
xianglong = arg
time.sleep(2)
print(xianglong)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
输出结果
9 9 9 9 9 9 9 9 9 9
可以看到,由于所以的线程都在修改同一个全局变量,导致最后无法得到想要的结果
使用threading.loacl
from threading import Thread
from threading import local
import time
from threading import get_ident
# 特殊的对象
xianglong = local()
def task(arg):
# 对象.val = 1/2/3/4/5
xianglong.value = arg
time.sleep(2)
print(xianglong.value)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
输出结果
0 1 2 3 5 4 6 7 8 9
使用了threading.local会为每一个线程创建一个独立的空间存储变量
get_ident
我们可以通过get_ident来获取每一个线程的独特的值,类似于线程号
from threading import Thread
from threading import get_ident
def task(arg):
print(get_ident())
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
输出结果
5028 6088 7340 8384 8648 3372 8752 5620 6308 4396
自己写一个类似于threading的功能
try:
from greenlet import getcurrent as get_ident
except Exception as e:
from threading import get_ident
from threading import Thread
import time
class Local(object):
def __init__(self):
object.__setattr__(self,'storage',{})
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
obj.xxx = arg
print(obj.val)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
用.给对象设置值时会调用__setattr__方法,这里我们导入时使用了try捕捉异常,先导入协程的get_ident,如果没有则导入线程的,所以我们的方法比threading.loacl多了一个实现协程的功能,不同的线程可以在obj对象的storage字典中利用自己的get_ident值为键生成对
应的值,在定义self.storage时我们调用的是父类object类的__setattr__方法,那是因为我们自己的类定义了这个方法,直接使用self.storage={}会执行自己类的__setattr__方法,会出问题
浙公网安备 33010602011771号