在Twisted中等待其他请求中的事件

时间:2011-03-03 08:22:49

标签: python twisted

我有一个简单的Twisted服务器来处理这样的请求(很明显,异步)

global SomeSharedMemory
if SomeSharedMemory is None:
    SomeSharedMemory = LoadSharedMemory()
return PickSomething(SomeSharedMemory)

从数据库加载SomeSharedMemory。

我想避免多次从数据库中加载SomeSharedMemory。具体来说,当服务器首次启动时,我们得到两个并发的传入请求,我们可能会看到如下内容:

请求1:检查SomeSharedMemory,找不到它 请求1:发出数据库查询以加载SSM 请求2:检查SSM,找不到它 请求2:发出数据库查询以加载SSM 请求1:查询返回,存储SSM 请求1:返回结果 请求2:查询返回,存储SSM 请求2:返回结果

随着更多并发请求,数据库受到重创。我想做这样的事情(见http://docs.python.org/library/threading.html#event-objects):

global SomeSharedMemory, SSMEvent
if SomeSharedMemory is None:
    if not SSMEvent.isSet():
        SSMEvent.wait()
    else:
        # assumes that the event is initialized "set"
        SSMEvent.clear()
        SomeSharedMemory = LoadSharedMemory()
        SSMEvent.set()
return PickSomething(SomeSharedMemory)

这样,如果一个请求正在加载共享内存,其他请求将礼貌地等待,直到查询完成,而不是发出自己的重复数据库查询。

这在扭曲中是否可行?

1 个答案:

答案 0 :(得分:2)

您的示例设置方式,很难看出您实际上是如何解决您所描述的问题。如果第二个请求在第一个请求进入第一个请求的LoadSharedMemory之前进入您的Twisted服务器,则第二个请求将在处理之前等待。当它最终被处理时,SomeSharedMemory将被初始化,并且不会重复。

但是,我想也许LoadSharedMemory是异步的并返回Deferred,这样你的代码看起来更像是这样:

def handleRequest(request):
    if SomeSharedMemory is None:
        d = initSharedMemory()
        d.addCallback(lambda ignored: handleRequest(request))
    else:
        d = PickSomething(SomeSharedMemory)
    return d

在这种情况下,完全有可能第二个请求可能会在initSharedMemory关闭时完成。那么你最终会尝试初始化该状态的两个任务。

当然,要做的事情是注意到你拥有的第三个状态。不仅 un -initialized和initializ- ed ,还有initializ- ing 。所以代表那个州。我将它隐藏在initSharedMemory函数中,以使请求处理程序更加简单:

initInProgress = None

def initSharedMemory():
    global initInProgress
    if initInProgress is None:
        initInProgress = _reallyInit()
        def initialized(result):
            global initInProgress, SomeSharedMemory
            initInProgress = None
            SomeSharedMemory = result
        initInProgress.addCallback(initialized)
    d = Deferred()
    initInProgress.chainDeferred(d)
    return d

由于各地的全局变量,这有点粗略。这是一个稍微清洁的版本:

from twisted.internet.defer import Deferred, succeed

class SharedResource(object):
    def __init__(self, initializer):
        self._initializer = initializer
        self._value = None
        self._state = "UNINITIALIZED"
        self._waiting = []


    def get(self):
        if self._state == "INITIALIZED":
            # Return the already computed value
            return succeed(self._value)

        # Create a Deferred for the caller to wait on
        d = Deferred()
        self._waiting.append(d)

        if self._state == "UNINITIALIZED":
            # Once, run the setup
            self._initializer().addCallback(self._initialized)
            self._state = "INITIALIZING"

        # Initialized or initializing state here
        return d


     def _initialized(self, value):
         # Save the value, transition to the new state, and tell
         # all the previous callers of get what the result is.
         self._value = value
         self._state = "INITIALIZED"
         waiting, self._waiting = self._waiting, None
         for d in waiting:
             d.callback(value)


SomeSharedMemory = SharedResource(initializeSharedMemory)

def handleRequest(request):
    return SomeSharedMemory.get().addCallback(PickSomething)

三个状态,它们之间有明确的显式转换,没有要更新的全局状态(至少如果你给SomeSharedMemory一些非全局范围),而handleRequest不知道任何这个,它只是要求一个值,然后使用它。