Есть страница часто задаваемых вопросов по Python, на которой указано, какие мутации считаются потокобезопасными (хотя я до сих пор не понимаю почему здесь атомарность подразумевает потокобезопасность)
Есть также страница глоссария, в которой немного рассказывается о GIL и говорится:
Этот [GIL] упрощает реализацию CPython путем создания объектной модели (включая важные встроенные типы, такие как dict
Итак, мое нынешнее понимание следующее:
- GIL гарантирует, что в любой момент времени выполняются только инструкции одной виртуальной машины (не Python).
- Некоторые операции над встроенными типами декомпилируются ровно в один байт-код. инструкцию, которую можно считать потокобезопасной (в данном контекст)
Код: Выделить всё
def inc(stats):
stats["ok"] = stats["ok"] + 1
код>)
Код: Выделить всё
0 LOAD_FAST 0 (stats)
2 LOAD_CONST 1 ('ok')
4 BINARY_SUBSCR
6 LOAD_CONST 2 (1)
8 BINARY_ADD
10 LOAD_FAST 0 (stats)
12 LOAD_CONST 1 ('ok')
14 STORE_SUBSCR
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
Код: Выделить всё
BINARY_SUBSCRНесмотря на это, многократный запуск этой функции с использованием concurrent.futures.ThreadPoolExecutor всегда дает согласованный результат. результаты (т. е. отсутствие условий гонки)
То же самое происходит и с другими подозрительно небезопасными операциями, такими как x = x + 1 (которые также дают согласованные результаты)
Если я правильно понимаю, иногда следует ожидать состояния гонки.
Я подозреваю одно или несколько из следующих событий:
- Мое понимание неверно.
- В CPython предусмотрена специальная обработка словарных операций.
- Эта операция выполняется достаточно быстро, поэтому Планировщик потоков Python не может вытеснить поток в середине выполнения оператора (не bytecode)
Подробнее здесь: https://stackoverflow.com/questions/792 ... -in-python
Мобильная версия