参考博客
一、线程特定的数据
在线程中有些资源需要锁定(如Lock, RLock, Condition, Semaphore)以供多个线程使用,有些资源需要保护,以使它们对并非是这些资源的“所有者”隐藏。
local()函数回创建一个对象,它能够隐藏值,使其在不同线程中无法被看到,除非在某个线程中设置了这个属性。
- 例1:
from threading import Thread
ret = -10
def task(args):
global ret
ret = args
print(ret)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
输出为
0
1
2
3
4
5
6
7
8
9
- 例2:在print(i)之前,让程序执行某个io操作
from threading import Thread
import time
ret = -10
def task(args):
global ret
ret = args
time.sleep(2)
print(ret)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
输出
9
9
9
9
9
9
9
9
9
9
- 例3:使用threading.local()开创局部空间,保存当前变量
from threading import Thread, local
import time
ret = local()
def task(args):
ret = args
time.sleep(2)
print(ret)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
输出
0
1
2
3
4
5
8
7
6
9
threading.local()的作用就是为每个线程开辟一个独立的空间进行数据存储。
属性ret对所有线程都不可见,除非在某个线程中设置了这个属性,这个线程才能看见它。
二、初始化设置线程:所有线程开始时都有相同值
如果需要初始化设置以使所有线程在开始时都有相同的值,可以使用一个子类,并在init()中设置这些属性。
下面的代码对mysqlconn连接设置初始化,传入参数如下:
from threading import local
class MysqlConnManager(local):
def __init__(self, host, port, db, usr, pwd):
super().__init__()
self._host = host
self._port = port
self._db = db
self._usr = usr
self._pwd = pwd
self._conn = None
三、local源码
今天晚上脑子有点转不过来了,先贴上,过几天再看~
@contextmanager
def _patch(self):
impl = object.__getattribute__(self, '_local__impl')
try:
dct = impl.get_dict()
except KeyError:
dct = impl.create_dict()
args, kw = impl.localargs
self.__init__(*args, **kw)
with impl.locallock:
object.__setattr__(self, '__dict__', dct)
yield
class local:
__slots__ = '_local__impl', '__dict__'
def __new__(cls, *args, **kw):
if (args or kw) and (cls.__init__ is object.__init__):
raise TypeError("Initialization arguments are not supported")
self = object.__new__(cls)
impl = _localimpl()
impl.localargs = (args, kw)
impl.locallock = RLock()
object.__setattr__(self, '_local__impl', impl)
# We need to create the thread dict in anticipation of
# __init__ being called, to make sure we don't call it
# again ourselves.
impl.create_dict()
return self
def __getattribute__(self, name):
with _patch(self):
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if name == '__dict__':
raise AttributeError(
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
with _patch(self):
return object.__setattr__(self, name, value)
def __delattr__(self, name):
if name == '__dict__':
raise AttributeError(
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
with _patch(self):
return object.__delattr__(self, name)
网友评论