我有一个简单的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)
这样,如果一个请求正在加载共享内存,其他请求将礼貌地等待,直到查询完成,而不是发出自己的重复数据库查询。
这在扭曲中是否可行?
答案 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
不知道任何这个,它只是要求一个值,然后使用它。