Каков "правильный" способ сделать поток stoppable в Python, учитывая остановленные псевдоатомные единицы работы?
Я пишу программу на Python. Эта программа прерывается очень часто, взаимодействием пользователя (CRTL + C), а также другими программами, отправляющими различные сигналы, все из которых должны останавливать работу потока различными способами. Нить выполняет кучу единиц работы (я называю их "атомами" ) в последовательности.
Каждый атом может быть остановлен быстро и безопасно, поэтому сделать сам поток остановки довольно тривиальным, но мой вопрос: что такое "правильный", или канонический способ реализации потока с остановкой, заданный stoppable, pseudo -атомные работы должны быть выполнены?
Должен ли я опросить флаг stop_at_next_check
перед каждым атомом (пример ниже)? Должен ли я украсить каждый атом чем-то, что делает проверку флага (в основном то же, что и в примере, но скрыто в декораторе)? Или я должен использовать другую технику, о которой я не думал?
Пример (простая проверка остановленного флага):
class stoppable(Thread):
stop_at_next_check = False
current_atom = None
def __init__(self):
Thread.__init__(self)
def do_atom(self, atom):
if self.stop_at_next_check:
return False
self.current_atom = atom
self.current_atom.do_work()
return True
def run(self):
#get "work to be done" objects atom1, atom2, etc. from somewhere
if not do_atom(atom1):
return
if not do_atom(atom2):
return
#...etc
def die(self):
self.stop_at_next_check = True
self.current_atom.stop()
Ответы
Ответ 1
Проверка флагов кажется правильной, но вы упустили возможность упростить ее, используя список для атомов. Если вы помещаете атомы в список, вы можете использовать одиночный цикл, не нуждаясь в методе do_atom()
, и проблема того, где делать проверку, решает сам.
def run(self):
atoms = # get atoms
for atom in atoms:
if self.stop_at_next_check:
break
self.current_atom = atom
atom.do_work()
Ответ 2
Создайте флаг "thread x should continue processing", и когда вы закончите с потоком, установите флаг в false.
Убийство потока напрямую считается плохим, потому что вы можете получить дробную часть работы.
Ответ 3
Чуть позже, но я создал небольшую библиотеку, муравьи, для решения этой проблемы. В вашем примере атомная единица представлена рабочим
пример
from ants import worker
@worker
def hello():
print("hello world")
t = hello.start()
...
t.stop()
В приведенном выше примере hello() будет запускаться в отдельном потоке, вызываемом через цикл while True:
тем самым выпуская "мир приветствия" как можно быстрее.
Вы также можете иметь триггерные события, например, выше, замените hello.start()
на hello.start(lambda: time.sleep(5))
и вы будете запускать его каждые 5: секунду
Библиотека очень новая и работа над GitHub продолжается https://github.com/fa1k3n/ants.git
Будущая работа включает в себя добавление colony
для нескольких работников, работающих над разными частями одних и тех же данных, а также планирование queen
для общения и контроля работников, таких как синхронизация