如何跨所有实例创建同步函数 [英] How to create a synchronized function across all instances

查看:81
本文介绍了如何跨所有实例创建同步函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想针对类的所有实例上的某些CRUD函数在python中创建一个同步方法.例如,当create被线程调用并正在进行时,delete需要在同一对象上等待.

I want to create a synchronized method in python with respect to some CRUD functions on all instances of a class. For example while create is called and ongoing by a thread, delete needs to wait on the same object.

有人可以告诉我下面的代码是否正确.我可能会遇到一些语法错误,但是我想知道的是,在创建此类的所有实例的调用中,锁是否将相同,因此,是否正在进行任何实例创建/删除,请在相同或其他实例上进行删除/创建.由另一个线程实例将不得不等待吗?

Can someone please tell me if the code below is correct. I may have some syntax error but what I want to know is if the lock is going to be the same across calls to create ALL instances of this class and therefore if any instance create/delete is in progress delete/create on the same or other instances by another thread will have to wait?

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 

我对python同步的理解将为每个create/delete函数对象调用. 我在锁定对象的上面的同步函数中添加了一条打印语句,并使用以下命令进行了测试:

My understanding of python is synchronized will be called for each of create/delete function object. I put a print statement in the synchronized function above for the lock object and did a test run using the following:

@synchronized
def test1():
    print "test1"


@synchronized
def test2():
    print "test2"

我得到以下输出,这使我认为两个函数对象使用的锁是相同的.我似乎不明白它是如何工作的.

And I get the following output, which makes me think the lock used is the same for both function objects. I don't seem to understand how this works.

<Semaphore c=1 _w[0]>
<Semaphore c=1 _w[0]>
test1
test2

推荐答案

您的输出将打印相同的<Semaphore c=1 _w[0]>,但不一定表示这些对象是相同的对象.这取决于您的print语句.

Your output prints the same <Semaphore c=1 _w[0]> but it doesn't necessarily indicate that those are the same objects. It depends what your print statement is.

要确保您没有使用相同的Lock对象,可以在_wrap函数中添加print语句,如下所示:

To make sure you are not using the same Lock object you could add a print statement in the _wrap function as follow:

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

每次您都会打印出一个不同的 id 呼叫createdelete:

You will get a different id printed every time you call create or delete:

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仅调用两次-当解释器读取装饰的方法声明时.装饰器使用_wrap的实现替换"装饰的方法,但不替换functools.wraps(wrapped)之上的内容,因此Lock每个装饰方法仅创建一次.

The decorator synchronized is only call twice - when the interpreter reads the decorated method declaration. The decorator "replace" the decorated method with the implementation of _wrap but not with what is above functools.wraps(wrapped) so the Lock is only created once per decorated method.

每个装饰方法都有自己的Lock.

Each decorated method has its own Lock.

在上面的代码中,我们还可以看到它适用于AtomicCRUD的任何实例,因为我们每次都重新实例化一个对象,但是使用单个实例时结果是相同的

In the code above we can also see that this works for any instance of AtomicCRUD since we re-instantiate an object every time but the result is the same when using a single instance

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的行为符合预期:

And with a complete example we can see that the Locks behave as expected:

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可以从不同的线程同时调用.

The output shows that create cannot be called at the same time from different threads. But delete and create can be called at the same time from different thread.

这篇关于如何跨所有实例创建同步函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆