Используя глобальный словарь с потоками в Python

Возможно, пример от рубина может помочь:

можно включать смешивание Comparable и определить одну функцию "<=>(other)", смешивание обеспечивает все те функции:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

Это делает это путем вызова <=>(other) и возвращения правильного результата.

"instance <=> other" возвраты 0, если оба объекта равны, меньше чем 0, если instance больше, чем other и больше чем 0, если other больше.

34
задан Alex 21 August 2009 в 14:33
поделиться

3 ответа

Предполагая, что CPython: да и нет. Фактически безопасно извлекать / сохранять значения из общего словаря в том смысле, что несколько одновременных запросов на чтение / запись не повредят словарь. Это происходит из-за глобальной блокировки интерпретатора («GIL»), поддерживаемой реализацией. То есть:

Поток A запущен:

a = global_dict["foo"]

Поток B запущен:

global_dict["bar"] = "hello"

Поток C запущен:

global_dict["baz"] = "world"

не повредит словарь, даже если все три попытки доступа происходят в «одно и то же» время. Интерпретатор будет сериализовать их каким-то неопределенным способом.

Однако результаты следующей последовательности не определены:

Поток A:

if "foo" not in global_dict:
   global_dict["foo"] = 1

Поток B:

global_dict["foo"] = 2

, поскольку тест / набор в потоке A не является атомарным (состояние гонки "время проверки / время использования"). Итак, обычно лучше, если вы заблокируете вещи:

from threading import RLock

lock = RLock()

def thread_A():
    lock.acquire()
    try:
        if "foo" not in global_dict:
            global_dict["foo"] = 1
    finally:
        lock.release()

def thread_B():
    lock.acquire()
    try:
        global_dict["foo"] = 2
    finally:
        lock.release()
52
ответ дан 27 November 2019 в 16:08
поделиться

Лучший, самый безопасный и переносимый способ заставить каждый поток работать с независимыми данными:

import threading
tloc = threading.local()

Теперь каждый поток работает с полностью независимым объектом tloc , даже если это глобальное имя. Поток может получать и устанавливать атрибуты в tloc , использовать tloc .__ dict __ , если ему специально нужен словарь и т. Д.

Локальное хранилище потока для потока исчезает в конце нить; чтобы потоки записывали свои окончательные результаты, попросите их поместить свои результаты до их завершения в общий экземпляр Queue.Queue (который изначально является потокобезопасным). Точно так же начальные значения для данных, над которыми должен работать поток, могут быть аргументами, переданными при запуске потока, или взяты из очереди .

Другие полусырые подходы, например, надежда на то, что операции, которые выглядят атомарными, действительно являются атомарными, могут работать для определенных случаев в данной версии и выпуске Python, но могут быть легко нарушены обновлениями или портами. Нет никаких реальных причин рисковать такими проблемами, когда правильная, чистая, безопасная архитектура настолько проста в организации, портативна, удобна и быстра.

25
ответ дан 27 November 2019 в 16:08
поделиться

GIL позаботится об этом, если вы используете CPython .

глобальная блокировка интерпретатора

Блокировка, используемая Потоки Python, чтобы гарантировать, что на виртуальной машине CPython одновременно выполняется только один поток. Это упрощает реализацию CPython, гарантируя, что никакие два процесса не могут обращаться к одной и той же памяти одновременно. Блокировка всего интерпретатора упрощает многопоточность интерпретатора за счет большей части параллелизма, обеспечиваемого многопроцессорными машинами. В прошлом предпринимались попытки создать интерпретатор со «свободным потоком» (который блокирует совместно используемые данные с гораздо более высокой степенью детализации), но до сих пор ни одна из них не увенчалась успехом, поскольку в обычном однопроцессорном случае снижалась производительность.

5
ответ дан 27 November 2019 в 16:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: