我想在python中创建一个与类的所有实例上的某些CRUD函数相关的同步方法。例如,当线程调用并执行create时,delete需要等待同一个对象。
有人可以告诉我以下代码是否正确。我可能有一些语法错误,但我想知道的是,如果锁定在创建此类的所有实例的调用之间是相同的,因此如果任何实例创建/删除正在进行中删除/创建相同或其他另一个线程的实例将不得不等待?
import threading
import functools
def synchronized(wrapped):
lock = threading.Lock()
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
with lock:
return wrapped(*args, **kwargs)
return _wrap
class AtomicCRUD(object):
@synchronized
def create(self):
#Do stuff that may take a while here.
pass
@synchronized
def delete(self):
#Do stuff that may take a while here.
pass
我将为每个create / delete函数对象调用我对python的同步理解。 我在上面的锁定对象的同步函数中放置了一个print语句,并使用以下命令运行了测试:
@synchronized
def test1():
print "test1"
@synchronized
def test2():
print "test2"
我得到以下输出,这让我觉得两个函数对象使用的锁是相同的。我似乎不明白这是如何运作的。
<Semaphore c=1 _w[0]>
<Semaphore c=1 _w[0]>
test1
test2
答案 0 :(得分:4)
您的输出打印相同的<Semaphore c=1 _w[0]>
,但它并不一定表示这些是相同的对象。这取决于您的print
声明是什么。
要确保您没有使用相同的Lock
对象,可以在print
函数中添加_wrap
语句,如下所示:
def synchronized(wrapped):
lock = threading.Lock()
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
print "Calling '%s' with Lock %s" % (wrapped.__name__, id(lock))
with lock:
return wrapped(*args, **kwargs)
return _wrap
每次拨打create
或delete
时,您都会收到不同的id
:
AtomicCRUD().delete()
# Calling 'delete' with Lock 3075170560
AtomicCRUD().delete()
# Calling 'delete' with Lock 3075170560
AtomicCRUD().create()
# Calling 'create' with Lock 3075170544
AtomicCRUD().create()
# Calling 'create' with Lock 3075170544
装饰器synchronized
仅调用两次 - 当解释器读取装饰的方法声明时。装饰者&#34;替换&#34;带有_wrap
实现的修饰方法,但不包含functools.wraps(wrapped)
以上的内容,因此每个修饰方法只创建一次Lock
。
每个装饰方法都有自己的Lock
。
在上面的代码中,我们也可以看到这适用于AtomicCRUD
的任何实例,因为我们每次都重新实例化一个对象,但是当使用单个实例时结果是相同的
crud = AtomicCRUD()
crud.delete()
# Calling 'delete' with Lock 3075059968
crud.delete()
# Calling 'delete' with Lock 3075059968
crud.create()
# Calling 'create' with Lock 3075059952
crud.create()
# Calling 'create' with Lock 3075059952
通过一个完整的例子,我们可以看到Lock
的行为符合预期:
import threading
import functools
import time
def synchronized(wrapped):
lock = threading.Lock()
print lock, id(lock)
@functools.wraps(wrapped)
def _wrap(*args, **kwargs):
with lock:
print ("Calling '%s' with Lock %s from thread %s [%s]"
% (wrapped.__name__, id(lock),
threading.current_thread().name, time.time()))
result = wrapped(*args, **kwargs)
print ("Done '%s' with Lock %s from thread %s [%s]"
% (wrapped.__name__, id(lock),
threading.current_thread().name, time.time()))
return result
return _wrap
class AtomicCRUD(object):
@synchronized
def create(self):
#Do stuff that may take a while here.
time.sleep(1)
@synchronized
def delete(self):
#Do stuff that may take a while here.
time.sleep(1)
class SyncThread(threading.Thread):
def __init__(self, crud, name):
super(self.__class__, self).__init__(name=name)
self._crud = crud
def run(self):
self._crud.create()
self._crud.delete()
crud = AtomicCRUD()
threads = [SyncThread(crud, "Thread_%d" % i) for i in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()
输出显示无法从不同的线程同时调用create
。但是delete
和create
可以从不同的线程同时调用。