Python Threads-Критический Раздел
Что такое "критический раздел" потока (в Python)?
поток входит в критическую секцию вызвав метод acquire (), который может быть блокирование или неблокируемый. Поток выходит из критическую секцию, вызывая метод release ().
- понимание потоков в Python, Linux Gazette
кроме того, какова цель блокировки?
3 ответов
критический раздел кода-это тот, который может выполняться только одним потоком за раз. Возьмем, к примеру, чат-сервер. Если у вас есть поток для каждого соединения (т. е. каждого конечного пользователя), один "критический раздел" - это код буферизации (отправка входящего сообщения всем клиентам). Если несколько нитей попытаются катить сообщение одновременно, вы получите переплетение Bfritos Mantwd PIoEmesCEsaSges, что, очевидно, совсем не хорошо.
замок-это то, что можно использовать для синхронизировать доступ к критическому разделу (или ресурсам в целом). В нашем примере сервера чата блокировка похожа на запертую комнату с пишущей машинкой. Если один поток находится там (для ввода сообщения), никакой другой поток не может попасть в комнату. Как только первая нить закончена, он отпирает комнату и уходит. Затем еще одна нить может идти в комнату (запирая ее). Замок означает "я получаю комнату"."
другие люди дали очень хорошие определения. Вот классический пример:
import threading
account_balance = 0 # The "resource" that zenazn mentions.
account_balance_lock = threading.Lock()
def change_account_balance(delta):
global account_balance
with account_balance_lock:
# Critical section is within this block.
account_balance += delta
скажем,+=
оператор состоит из трех подкомпонентов:
- читать текущее значение
- добавьте RHS к этому значению
- запишите накопленное значение обратно в LHS (технически bind это в терминах Python)
если у вас нет with account_balance_lock
заявление и вы выполняете два change_account_balance
звонки параллельно вы можете в конечном итоге чередования трех операций подкомпонент в опасной манере. Допустим, вы одновременно звоните change_account_balance(100)
(он же pos) и change_account_balance(-100)
(он же neg). Это могло случиться:
pos = threading.Thread(target=change_account_balance, args=[100])
neg = threading.Thread(target=change_account_balance, args=[-100])
pos.start(), neg.start()
- pos: читать текущее значение - > 0
- neg: читать текущее значение - > 0
- pos: добавить текущее значение для чтения значения - > 100
- neg: добавить текущее значение для чтения значения -> -100
- pos: записать текущее значение -> account_balance = 100
- neg: записать текущее значение - > account_balance = -100
поскольку вы не заставляли операции происходить в дискретных кусках, вы можете иметь три возможных результата (-100, 0, 100).
на with [lock]
оператор-это одна неделимая операция, которая говорит: "Позвольте мне быть единственным потоком, выполняющим этот блок кода. Если что-то еще исполняется, это круто-я подожду."Это гарантирует, что обновления account_balance
несколько "потокобезопасный" (parallelism-safe).
Примечание: есть оговорка к этой схеме: вы должны помнить, чтобы получить account_balance_lock
(via with
) каждый раз, когда вы хотите манипулировать account_balance
чтобы код оставался потокобезопасным. Есть способы сделать это менее хрупким, но это ответ на совершенно другой вопрос.
Edit: в ретроспективе, вероятно, важно упомянуть, что with
оператор неявно вызывает блокировку acquire
on the lock -- это часть" я подожду " диалогового окна выше потока. Напротив, неблокирующее приобретение говорит:" Если я не могу получить замок сразу, дайте мне знать", а затем полагается на вас, чтобы проверить, получили ли вы замок или нет.
import logging # This module is thread safe.
import threading
LOCK = threading.Lock()
def run():
if LOCK.acquire(False): # Non-blocking -- return whether we got it
logging.info('Got the lock!')
LOCK.release()
else:
logging.info("Couldn't get the lock. Maybe next time")
logging.basicConfig(level=logging.INFO)
threads = [threading.Thread(target=run) for i in range(100)]
for thread in threads:
thread.start()
я также хочу добавить, что основная цель замка-гарантировать атомарность приобретения (неделимость acquire
через потоки), который простой логический флаг не гарантирует. Семантика атомарного операции возможно также содержание другой вопрос.
A "критическую секцию" - Это фрагмент кода, в котором для корректности необходимо убедиться, что в этом разделе может находиться только один поток управления. В общем, вам нужен критический раздел, чтобы содержать ссылки, которые написать значения в память, которые могут быть разделены между более чем одним параллельным процессом.