Безопасность потоков в словаре Python - PullRequest
84 голосов
/ 05 августа 2011

У меня есть класс, который содержит словарь

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

И я запускаю 4 потока (по одному для каждого ресторана), которые вызывают метод OrderBook.addOrder.Вот функция, выполняемая каждым потоком:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

Это безопасно, или мне нужно использовать блокировку перед вызовом addOrder?

Ответы [ 3 ]

75 голосов
/ 05 августа 2011

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

Ваш код должен быть безопасным. Имейте в виду: замок здесь почти не добавит накладных расходов и даст вам душевное спокойствие.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm имеет более подробную информацию.

26 голосов
/ 05 августа 2011

Да, встроенные типы по своей природе поточно-ориентированы: http://docs.python.org/glossary.html#term-global-interpreter-lock

Это упрощает реализацию CPython, делая объектную модель ( включая критические встроенные типы, такие как dict ), неявно защищенной от одновременного доступа.

3 голосов

Стоит отметить, что руководство по стилю Google рекомендует не полагаться на атомарность, как я объяснил более подробно на: Является ли назначение переменных Python атомарным?

Не полагайтесь на атомарность встроенных типов.

Хотя встроенные типы данных Python, такие как словари, по-видимому, имеют атомарные операции, существуют угловые случаи, когда они не атомарны (например, если __hash__ или __eq__ реализованы как методы Python) и их атомарность не должна полагаться. Также не следует полагаться на атомарное присвоение переменных (поскольку это, в свою очередь, зависит от словарей).

Используйте тип данных Queue модуля Queue в качестве предпочтительного способа передачи данных между потоками. В противном случае используйте модуль потоков и его блокирующие примитивы. Узнайте о правильном использовании условных переменных, чтобы вы могли использовать threading.Condition вместо блокировок более низкого уровня.

И я согласен с этим: в CPython уже есть GIL, поэтому снижение производительности при использовании Lock будет незначительным. Гораздо дороже будут потраченные часы на поиск ошибок в сложной кодовой базе, когда эти детали реализации CPython изменятся за один день.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...