如何跨所有实例创建同步函数

时间:2015-03-20 02:16:53

标签: python multithreading decorator

我想在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

1 个答案:

答案 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

每次拨打createdelete时,您都会收到不同的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。但是deletecreate可以从不同的线程同时调用。