Остановить поток: флаг против события [дубликат]
На этот вопрос уже есть ответ здесь:
- потоки Python и атомарные операции 2 ответа
Я видел примеры например, здесь использования Event
Чтобы остановить поток, где я думаю, что логический флаг будет делать эту работу.
Событие
class MyThread(threading.Thread):
def __init__(self):
self._please_stop = threading.Event()
def run(self):
while not self._please_stop.is_set():
[...]
def stop(self):
self._please_stop.set()
Флаг
class MyThread(threading.Thread):
def __init__(self):
self._please_stop = False
def run(self):
while not self._please_stop:
[...]
def stop(self):
self._please_stop = True
Какая польза от использования Event
здесь? Его Метод wait
не используется. Что делает его лучше, чем логический флаг?
Я вижу смысл, если один и тот же Event
разделяется между несколькими потоками, но в остальном я его не понимаю.
Этот поток рассылки предполагает, что Event
будет безопаснее, но мне непонятно, почему.
Точнее, я не понимаю эти два абзаца:
Если я правильно понимаю GIL, он синхронизирует весь доступ к Структуры данных Python (такие как my boolean флаг "прекращено"). Если что в таком случае, зачем утруждать себя использованием резьбы.Мероприятие для этой цели?
GIL является деталью реализации и полагается на нее для синхронизации вещи для вас не защищают от будущего. У вас, вероятно, будет много предупреждение, но с использованием резьбы.Event () не сложнее, и это больше правильно и безопаснее в долгосрочной перспективе.
Я согласен, что использование Event
добавляет почти никаких накладных расходов, поэтому я могу придерживаться этого, но я хотел бы понять пределы флаг приближается.
(я использую Python3, поэтому меня не волнуют ограничения Python2, если таковые имеются, хотя они полностью заслуживают упоминания здесь.)
2 ответа:
Я думаю, что подразумевается в потоке, который вы цитируете, что установка булева не обязательно является атомной операцией в Python. В то время как наличие глобальной блокировки на всех объектах Python (GIL) делает все операции, устанавливающие атрибут , атомарными на данный момент, такая блокировка может не существовать в будущем. Использование
Event
делает операцию атомарной, поскольку она использует собственную блокировку для доступа.Ссылка для atomic - это вопрос Java, но он не менее важен, потому что об этом.
Программирование часто заключается не только в том, чтобы заставить код работать сегодня, но и в том, чтобы заставить его работать через изменения, которые будут сделаны в будущем.
Таким образом, вполне вероятно, что вы можете писать многопоточные программы совершенно правильно на Python, полагаясь на то, как байт-код прерывается и когда GIL может быть выпущен... но если я буду читать и изменять ваш код позже, я был бы гораздо счастливее, если бы вы использовали стандартные примитивы синхронизации.
- другие реализации Python не имеют GIL. Захочу ли я запустить его на pypy завтра?
На самом деле, мне нужно распределить работу по нескольким процессам. Поменяйтесь местамиmultiprocessing
... который реализуетEvent()
, но потерпит неудачу, если вы просто используете локальную переменную.- Получается, что код должен остановиться только в том случае, если несколько других нитей считают, что так и должно быть. Ну, используйте
Semaphore()
вместоEvent()
... но было бы легко реализовать неправильно с переменными.