标签:说明 获取 切换 pre range 需求 cal code 问题
from threading import Thread, get_ident # 可以获取线程id
import time
num = -1
def task(arg):
global num
num = arg
time.sleep(2)
print(num, f‘线程{get_ident()}‘)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
"""
9 线程12244
9 线程13324
9 线程7972
9 线程134249
9 线程12476
9 线程13408
...
"""
很明显, 数据改乱了, 是个线程更改的都是同一份数据, 对数据产生了不安全性
为了让他们的更改相互隔离, 于是就可以 :
- 加锁 : 不使用该方法, 加锁的思路是多个线程要真正实现共用一个数据, 而我们是要做请求对象的并发, 实现的是该线程对于请求对象这部分内容有任何修改并不影响其他线程
- 所以使用 local 对象将要修改的数据复制一份,使得每个数据互不影响
from threading import Thread
from threading import local
from threading import get_ident
import time
# local对象,当识别到新的进程会为其开辟一块新的内存空间, 相当于每个线程都对该值进行了拷贝
local_obj = local()
‘‘‘
{‘线程1‘:{‘value‘:1},‘线程2‘:{‘value‘:1},‘线程3‘:{‘value‘:1},‘线程4‘:{‘value‘:1}}
‘‘‘
def task(arg):
local_obj.value = arg
time.sleep(2)
print(local_obj.value,f‘线程号:{get_ident()}‘)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
"""
2 线程号:11896
3 线程号:8796
9 线程号:3100
8 线程号:9188
....
"""
from threading import get_ident, Thread
storage = {} # 初始化一个字典
‘‘‘
{‘线程1‘:{‘value‘:1},‘线程2‘:{‘value‘:1},‘线程3‘:{‘value‘:1},‘线程4‘:{‘value‘:1}}
‘‘‘
def set(k, v):
# 获取线程id
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()
"""
0
1
2
3
4
5
6
7
8
9
"""
from threading import get_ident, Thread
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()
setattr
,getattr
from threading import get_ident, Thread
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()
上面已经实现了 local 的功能, 但存在一个问题 : 如果我们想生成多个local对象,但是会导致多个local对象所管理的线程设置的内容都放到了类属性
storage = { }
里面, 于是我们可以想到将 storage 设置成对象属性
storage = { }
设置成对象属性, 实现每一个local对象所对应的线程设置的内容都放到自己的storage里面from threading import get_ident, Thread
class Local(object):
def __init__(self):
object.__setattr__(self, ‘storage‘, {})
# self.__setattr__(‘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
print(obj.val)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
werkzeug
包, 我们导入werkzeug
下的local
查看其源码try:
from greenlet import getcurrent as _get_ident # 获取协程唯一标识
except ImportError:
from threading import get_ident as _get_ident # 获取线程唯一标识
_get_ident
,并且先导入协程模块的时候如果报错说明不支持协程,就会去导入线程的_get_ident
,这样无论是只有线程运行还是协程运行都可以获取唯一标识try:
from greenlet import getcurrent as get_ident # 获取协程唯一标识
except Exception as e:
from threading import get_ident # 获取进程唯一标识
from threading import Thread
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()
标签:说明 获取 切换 pre range 需求 cal code 问题
原文地址:https://www.cnblogs.com/songhaixing/p/14851640.html