Как настроен ваш пример, трудно понять, как у вас может возникнуть проблема, которую вы описываете.Если второй запрос поступит на ваш Twisted сервер до того, как будет возвращен вызов LoadSharedMemory
, выданный первым, тогда второй запрос просто будет ждать обработки.Когда он будет окончательно обработан, 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 -инициализированная и инициализированная ed , но и инициализируемая 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
нетзнать обо всем этом, он просто запрашивает значение и затем использует его.