#python #concurrency #race-condition
#python #параллелизм #состояние гонки
Вопрос:
У меня есть 2 процесса: Start и Status. Одновременно может выполняться несколько процессов запуска, и должен быть только 1 экземпляр процесса состояния.
При запуске процесса запуска он попытается запустить статус. На данный момент я пытаюсь остановить запуск нескольких статусов, заставляя процесс Status проверять, был ли привязан порт сервера Status, чтобы определить, существует ли другой статус, и если да, то он завершится корректно.
Однако у этого есть условие гонки, когда во время проверки привязанного порта может быть другой статус, который выполнил эту проверку и находится в процессе привязки этого порта, следовательно, будет создано 2 статуса.
Есть ли решение для этого на уровне процесса? Я рассматривал возможность использования другого процесса, отслеживающего количество статусов в системе, но есть ли другой подход?
Редактировать: это делается в Python 2.6
Edit2: как Start, так и Status извлекаются из оболочки.
Ответ №1:
Во-первых, вы можете использовать что-то вроде supervisord для координации выполнения процессов. На самом деле это неплохо. Вы в основном настраиваете свои процессы, максимальное число, которое может выполняться, И т. Д., И Он будет обрабатывать все остальное. Однако вам нужно разобраться со всеми небольшими элементами конфигурации. Вы также можете выделить этот процесс состояния в отдельный, если он выполняется как поток в другом процессе. Таким образом, вы добьетесь большего успеха.
Вероятно, вы можете сделать это менее проблематичным, если измените способ обработки этого. Вместо проверки, а затем выполнения, просто выполните и обработайте ошибку.
try:
open_port_listener()
except socket.error as e:
do_nothing()
Или, может быть, ввести немного более детальную проверку типа ошибки сокета. Я предполагаю, что вы используете socket
и получаете socket.error (возможно, адрес уже используется или что-то в этом роде?).
Если вы запускали это с помощью multiprocessing
модуля (который, как я знаю, вы не используете, поскольку вы уточнили, но я оставлю это на всякий случай, если это будет полезно для кого-либо еще), вы могли бы использовать блокировку, чтобы гарантировать, что проверка состояния процесса происходит в том или ином процессе. multiprocessing
Модуль поддерживает это. Прочитайте документы здесь.
from multiprocessing import Process, Lock
def startStatusProcess(l):
l.acquire()
if not do_check():
Process(target=runStatusProcess, args=()).start()
l.release()
if __name__ == '__main__':
lock = Lock()
startStatusProcess(lock)
Комментарии:
1. Я пытался читать документы, но в них нет подробностей о том, как работает блокировка в нескольких процессах. Поскольку может быть несколько процессов запуска, блокировка гарантирует только наличие только 1 статуса для этого процесса запуска? Или это касается всех процессов запуска?
2. В принципе,
acquire()
выдаст блокировку. Если второй процесс попытается выполнить попыткуacquire()
после первого, он заблокирует это утверждение до тех пор, пока не возникнут проблемы с первым процессомrelease()
. Это предотвращает выполнение проверки и выполнения процесса параллельно с проверкой и выполнением другого процесса. Просто имейте в виду, это должен быть один и тот жеLock()
объект.3. Кроме того, я предполагал, что вы используете
multiprocessing
модуль. Если это не так, и вы запускаете несколько исполнений из оболочки, тогда я бы выбрал что-то вродеsupervisord
.4. Запуск и статус выполняются из оболочки, извините за отсутствие этой детали в OP. Я обновлю его.
5. Да, я пытаюсь привязать, а затем перехватить ошибку сокета, чтобы узнать, используется ли она уже. Проблема в том, что я должен использовать другой обязательный сторонний уровень tcp / ip, поэтому, если он успешно привязан, я должен отменить привязку, а затем выполнить вызовы этого стороннего уровня. На этом этапе может возникнуть состояние гонки.
Ответ №2:
Вероятно, существуют способы pythonic, но я бы использовал супервизор процесса, такой как daemontools, systemd, runit и т. Д., Для запуска и контроля процесса состояния, чтобы убедиться, что он один и только один.