本文转载自:https://blog.csdn.net/qq_33961117/article/details/87645427
目录
二、Local组件的简单使用 - local对象.变量名 = 赋值
三、实现Local并使其兼容线程和协程 - 参考Flask源码
一、local 简单介绍
python3 - 多线程 - threading 模块(基于win系统)- Thread、Timer 组件
当多个线程修改同一个数据时,将该数据复制多份给每个线程单独使用,即为每个线程开辟一块空间进行数据存储
1-1 不使用local组件存在的弊端
多个线程同时操作同一个全局变量,每次操作都会修改值,存在锁机制。导致每个线程取到的起始数据不相同,导致最后结果输出错误。
-
# 未使用local
-
from threading import Thread
-
import time
-
-
test= -1
-
def task(arg):
-
global test
-
test= arg
-
# 模拟IO操作,用于实现对全局变量的混乱操作
-
time.sleep(2)
-
print(test)
-
-
for i in range(10):
-
t = Thread(target=task,args=(i,))
-
t.start()
-
-
'''
-
9
-
9
-
9
-
9
-
9
-
9
-
9
-
9
-
9
-
9
-
'''
二、Local组件的简单使用 - local对象.变量名 = 赋值
总结:由Local组件的简单使用可以看出Local操作类似于字典的操作。
-
from threading import Thread
-
from threading import local
-
import time
-
from threading import get_ident # get_ident用于获取线程、进程ID号
-
-
# 初始化local对象
-
loc= local()
-
-
def task(arg):
-
# 对象.val = 1/2/3/4/5
-
loc.value = arg
-
time.sleep(2)
-
print(loc.value)
-
-
for i in range(10):
-
t = Thread(target=task,args=(i,))
-
t.start()
-
-
'''
-
3
-
1
-
0
-
2
-
5
-
4
-
7
-
6
-
9
-
8
-
'''
2-1 自定义字典实现Local的操作
-
from threading import get_ident,Thread
-
import time
-
-
storage = {}
-
-
def set(k,v):
-
ident = get_ident()
-
if ident in storage:
-
storage[ident][k] = v
-
else:
-
storage[ident] = {k:v}
-
-
def get(k):
-
ident = get_ident()
-
return storage[ident][k]
-
-
def task(arg):
-
set('val',arg)
-
v = get('val')
-
print(v)
-
-
for i in range(10):
-
t = Thread(target=task,args=(i,))
-
t.start()
2-2 基于面对对象实现Local
-
from threading import get_ident,Thread
-
import time
-
-
class Local(object):
-
storage = {}
-
def set(self, k, v):
-
ident = get_ident()
-
if ident in Local.storage:
-
Local.storage[ident][k] = v
-
else:
-
Local.storage[ident] = {k: v}
-
def get(self, k):
-
ident = get_ident()
-
return Local.storage[ident][k]
-
-
obj = Local()
-
-
def task(arg):
-
obj.set('val',arg)
-
v = obj.get('val')
-
print(v)
-
-
for i in range(10):
-
t = Thread(target=task,args=(i,))
-
t.start()
2-3 基于魔法方法实现Local
-
from threading import get_ident,Thread
-
import time
-
-
class Local(object):
-
storage = {}
-
def __setattr__(self, k, v):
-
ident = get_ident()
-
if ident in Local.storage:
-
Local.storage[ident][k] = v
-
else:
-
Local.storage[ident] = {k: v}
-
def __getattr__(self, k):
-
ident = get_ident()
-
return Local.storage[ident][k]
-
-
obj = Local()
-
-
def task(arg):
-
obj.val = arg
-
print(obj.val)
-
-
for i in range(10):
-
t = Thread(target=task,args=(i,))
-
t.start()
2-4 基于魔法方法实现单独存储空间的Local
-
from threading import get_ident,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()
三、实现Local并使其兼容线程和协程 - 参考Flask源码
-
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()