Есть ли некоторые случаи, где потоки Python могут безопасно управлять общим состоянием?

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

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

Однако я не мог вызвать состояние состязания с атомарными операциями, такими как список, добавляет или переменные инкременты. Этот тест исчерпывающе пытается продемонстрировать такую гонку:

from threading import Thread, Lock
import operator

def contains_all_ints(l, n):
    l.sort()
    for i in xrange(0, n):
        if l[i] != i:
            return False
    return True

def test(ntests):
    results = []
    threads = []
    def lockless_append(i):
        results.append(i)
    for i in xrange(0, ntests):
        threads.append(Thread(target=lockless_append, args=(i,)))
        threads[i].start()
    for i in xrange(0, ntests):
        threads[i].join()
    if len(results) != ntests or not contains_all_ints(results, ntests):
        return False
    else:
        return True

for i in range(0,100):
    if test(100000):
        print "OK", i
    else:
        print "appending to a list without locks *is* unsafe"
        exit()

Я запустил тест выше без отказа (100x 100k многопоточный, добавляет). Кто-либо может заставить это перестать работать? Есть ли другой класс объекта, который может быть сделан неправильно себя вести через атомарный, возрастающее, модификацию потоками?

Они неявно 'атомарная' семантика относятся к другим операциям в Python? Разве это непосредственно связано с GIL?

5
задан Erik Garrison 29 April 2010 в 20:06
поделиться

2 ответа

Да, добавление к списку является потокобезопасным. Вы можете добавлять в список только GIL, и список заботится о том, чтобы не освободить GIL во время операции append (что, в конце концов, довольно простая операция). Порядок , в котором выполняются различные операции добавления потока, конечно, можно достать, но все они будут строго сериализованными операциями, потому что GIL никогда не освобождается во время добавления.

То же самое не обязательно верно для других операций. Многие операции в Python могут вызвать выполнение произвольного кода Python, что, в свою очередь, может вызвать выпуск GIL. Например, i + = 1 - это три разные операции: «получить i ',« добавить к нему 1 »и« сохранить в i »». добавить 1 к нему "переведет (в данном случае) в it .__ iadd __ (1) , который может срабатывать и делать все, что угодно.

Сами объекты Python охраняют свое внутреннее состояние - dicts не будут повреждены двумя разными потоками, пытающимися установить в них элементы. Но если данные в dict должны быть внутренне непротиворечивыми, ни dict, ни GIL не делают ничего для защиты этого, кроме (в обычном потоке) путем что делает это менее вероятным, но все же возможным все оказывается не так, как вы думали.

7
ответ дан 14 December 2019 в 04:32
поделиться

В CPython переключение потоков выполняется при выполнении байткодов sys.getcheckinteval (). Таким образом, переключение контекста никогда не может произойти во время выполнения одного байт-кода, а операции, которые закодированы как один байт-код, по своей сути являются атомарными и потокобезопасными, если только этот байт-код не выполняет другой код Python или не вызывает код C, который освобождает GIL. Большинство операций со встроенными типами коллекций (dict, list и т. Д.) Попадают в категорию «по своей сути потокобезопасные».

Однако это деталь реализации, которая специфична для реализации Python на языке C, и на нее не следует полагаться. Другие версии Python (Jython, IronPython, PyPy и т. Д.) Могут вести себя иначе. Также нет гарантии, что будущие версии CPython сохранят такое поведение.

1
ответ дан 14 December 2019 в 04:32
поделиться
Другие вопросы по тегам:

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