Предполагается, что вы используете глобальную переменную в set_x
:
x = None
def set_x():
global x
x = "foo"
def worker():
if not x:
set_x()
Существует условие гонки между if not x
и фактической установкой x.Таким образом, несколько потоков могут присвоить значение x
.Это в основном безвредно для неизменяемых объектов, но проблематично для изменяемых объектов, таких как списки, где переназначение теряет значения в существующем x
.И "главным образом" даже объекты, чьи значения сравниваются, могут иметь разные идентификаторы, поэтому ==
может работать, но is
может не работать:
>>> a = "foo"
>>> b = "bar"
>>> c = a + b
>>> d = a + b
>>> c == d
True
>>> c is d
False
И, конечно, пути кода, которые не воспроизводят *Игра 1013 * может обнаружить, что x
изменяется от None
до ожидаемого значения, пока они выполняются.
Тем более, что x
является дорогостоящим для вычисления, хорошим подходом является скрыть его за получателем.Теперь все должны играть в одну и ту же игру, и только один из потоков на самом деле сделает эту работу.
_x = None
_x_lock = threading.Lock()
def get_x():
global _x
if _x is None:
with _x_lock:
if _x is None:
_x = "foobar"
return _x