我写了一个我用作装饰的课程。我清楚地做的不是线程安全,而是需要。
这是一个非常简单的例子:
class DecoratorClass(object):
def __init__(self):
print 'initing DecoratorClass'
self.counter = 0
def __call__(self, func, *args, **kwargs):
def wrapped_func(*args, **kwargs):
print '\nin wrapped func, func name:', func.func_name
print 'count val:', self.counter
self.counter += 1
ret_val = func()
return ret_val
return wrapped_func
@DecoratorClass()
def decorated_with_class():
return
decorated_with_class()
decorated_with_class()
decorated_with_class()
这是输出:
initing DecoratorClass
in wrapped func, func name: decorated_with_class
count val: 0
in wrapped func, func name: decorated_with_class
count val: 1
in wrapped func, func name: decorated_with_class
count val: 2
所以我得到一个DecoratorClass实例,它在用它装饰的三个函数之间共享。有没有一种直接的方法在每次调用decorated_with_class()时获取一个新的DecoratorClass实例?或者其他一些使这个线程安全的方法(例如,让self.counter每次从0开始)?或者这是一个失败的原因?
编辑澄清:
为了简单起见,我故意省略了本例中的任何线程;我正在工作的环境将被线程化,但这个例子不是。
我实际上并没有计算生产代码中的任何内容。我真正的问题是我的装饰器类上有一个实例变量,它可以由两个在不同线程中运行的相同函数的实例更新。我只是使用计数器示例来表明装饰器类只获得一个实例,它保持状态。我需要每个线程/函数1.获取自己的装饰器类的实例或2.等待其他线程没有使用装饰器类。
答案 0 :(得分:1)
好的,这是我遇到的更好的例子:
import threading
import time
class DecoratorClass(object):
def __init__(self):
self.thread = None
def __call__(self, func, *args, **kwargs):
def wrapped_func(*args, **kwargs):
curr_thread = threading.currentThread().getName()
self.thread = curr_thread
print '\nthread name before running func:', self.thread
ret_val = func()
print '\nthread name after running func:', self.thread
return ret_val
return wrapped_func
@DecoratorClass()
def decorated_with_class():
print 'running decorated w class'
time.sleep(1)
return
threads = []
for i in range(5):
t = threading.Thread(target=decorated_with_class)
threads.append(t)
t.start()
输出:
thread name before running func: Thread-1
running decorated w class
thread name before running func: Thread-2
thread name before running func: running decorated w classThread-3
thread name before running func:
running decorated w class
thread name before running func:Thread-5
running decorated w class
Thread-5
running decorated w class
thread name after running func: Thread-5
thread name after running func: Thread-5
thread name after running func: Thread-5
thread name after running func: Thread-5
thread name after running func: Thread-5
因此,显然所有线程都使用相同的DecoratorClass实例,并且self.thread在所有线程完成运行时最终成为Thread-5(而不是实际运行代码的线程的名称) 。)
我只需要在我的装饰器中添加一个锁,就像这样:
class DecoratorClass(object):
def __init__(self):
self.thread = None
self.lock = threading.Lock()
def __call__(self, func, *args, **kwargs):
def wrapped_func(*args, **kwargs):
self.lock.acquire()
curr_thread = threading.currentThread().getName()
self.thread = curr_thread
print '\nthread name before running func:', self.thread
ret_val = func()
print '\nthread name after running func:', self.thread
self.lock.release()
return ret_val
return wrapped_func
@DecoratorClass()
def decorated_with_class():
print 'running decorated w class'
time.sleep(1)
return
threads = []
for i in range(5):
t = threading.Thread(target=decorated_with_class)
threads.append(t)
t.start()
现在我的输出看起来像这样,这就是我想要的:
thread name before running func: Thread-1
running decorated w class
thread name after running func: Thread-1
thread name before running func: Thread-2
running decorated w class
thread name after running func: Thread-2
thread name before running func: Thread-3
running decorated w class
thread name after running func: Thread-3
thread name before running func: Thread-4
running decorated w class
thread name after running func: Thread-4
thread name before running func: Thread-5
running decorated w class
thread name after running func: Thread-5
答案 1 :(得分:0)
我不清楚为什么你需要DecoratorClass
的多个实例,但是如果你刚刚将threading.Lock
添加到包装的函数线程安全中呢?
class DecoratorClass(object):
def __init__(self):
print 'initing DecoratorClass'
self.counter = 0
self._lock = Lock()
def __call__(self, func, *args, **kwargs):
def wrapped_func(*args, **kwargs):
with self._lock:
print '\nin wrapped func, func name:', func.func_name
print 'count val:', self.counter
self.counter += 1
ret_val = func()
return ret_val
return wrapped_func
答案 2 :(得分:0)
如果您有兴趣为每个装饰的功能维护计数器的副本,可以将其存储在功能本身中。请记住,函数是普通的Python对象:
将D
替换为
K
由于您的装饰器类将不再具有状态,您可以仅使用实现self.counter += 1
的函数替换它:
if hasattr(func, "counter"):
func.counter += 1
else:
func.counter = 0
答案 3 :(得分:0)
class DecoratorClass(object): def __init__(self): print 'initing DecoratorClass' self.counter = 0 def __call__(self, func, *args, **kwargs): def wrapped_func(*args, **kwargs): print '\nin wrapped func, func name:', func.func_name print 'count val:', self.counter self.counter += 1 ret_val = func() return ret_val return wrapped_func @DecoratorClass() def decorated1(): return @DecoratorClass() def decorated2(): return @DecoratorClass() def decorated3(): return decorated1() decorated2() decorated3()
让我
initing DecoratorClass initing DecoratorClass initing DecoratorClass in wrapped func, func name: decorated1 count val: 0 in wrapped func, func name: decorated2 count val: 0 in wrapped func, func name: decorated3 count val: 0
这有帮助吗?