#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import signal
import sys
from time import sleep
def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
print(a)
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
a = 0
while True:
a += 1
sleep(2)
a += 1
print(a)
Теперь я хочу в signal_handler сохранять состояние программы, для того чтобы не усложнять пример буду просто печатать a (хотя я не уверен что то как это сделано правильно). Понятно, что состояние когда a - нечётное число некорректно. Т.е. цикл надо досчитывать до конца. Вопрос в том, как это сделать наименее уродски. Да, отлавливать в цикле Ctrl+C нельзя, так как убивать может и мой скрипт на выключение компа, который гарантированно дождётся корректного завершения программы, работающей в фоне.
Конечно можно обмазаться каким-нибудь atomicloop, но боюсь это быдлокод будет в общем случае. Надо понять как это делать правильнее.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import signal
import sys
from time import sleep
def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
print(a)
global work
work = False
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
a = 0
work = True
while work:
a += 1
sleep(2)
a += 1
print(a)
боюсь что это не так работает. В реальной программе у нас нет возможности проверить что и как там сварилось, более того там в цикле результат классификации некоторых данных нейронной сетью/другими классификаторами, а сохраняем мы данные о том, что и чем проклассифицировалось, чтобы вернуться к дальнейшей классификации после перезапуска программы/перезагрузки сервера. Пример чисто синтетический, чтобы понять проблему.
Уже лучше, но нет. Потому что print(a) по прежнему выведет нечётное число, хотя дальше оно и досчитает до чётного, а значит этот момент не годится для сохранения состояния приложения.
Ну, я тогда не до конца уловил, что тебе нужно, но можешь маскировать SIGINT перед началом каждой итерации, а в конце итерации размаскировывать этот сигнал. Если где-то во время выполнения итерации прилетит SIGINT, то в конце итерации цикла программа завершится.
А у нас есть гарантия того, что маскировка успеет произойти? Т.е. не будет того, что сигнал разорвёт точно перед ней и будет каша? Просто я не настолько хорошо понимаю то как работают сигналы в питоне, чтобы быть уверенным в чём-то.
В начале программы устанавливаешь обработчик сигнала, когда еще нечего «сохранять».
Потом используешь обработчик сигнала, чтобы взвести переменную – условие выхода из цикла.
Выходишь из цикла штатным образом, когда внутренние данные корректны. Сохраняешь состояние.
Только для полноты картины нужно в конце снять обработчик сигнала и убить себя тем же номером сигнала, который был пойман ранее. Чтобы приложение завершилось с правильным кодом выхода.
Уже лучше, но нет. Потому что print(a) по прежнему выведет нечётное число, хотя дальше оно и досчитает до чётного, а значит этот момент не годится для сохранения состояния приложения.
Момент обработки сигнала не годится ни для чего, кроме подъёма флажка о том, что пришло время помереть. Сохранять состояние нужно после выхода из цикла.
Понял уже. Жаль что очень удобно обработку в одном месте не получится сделать. Будет разорванная логика. С учётом всего в треде выходит что-то вроде:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import signal
import os
from time import sleep
class PerfectKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
self.signal = None
def exit_gracefully(self, signum, frame):
self.signal = signum
self.kill_now = True
def perfect_exit(self):
if self.signal is not None:
signal.signal(self.signal, signal.SIG_DFL)
os.kill(os.getpid(), self.signal)
print('Press Ctrl+C')
a = 0
killer = PerfectKiller()
while not killer.kill_now:
a += 1
sleep(2)
a += 1
print(a)
print(f'типо сохранение {a}')
killer.perfect_exit()
Внимание вопрос, особенно к wandrien не налажал ли я где-то тут? Оно вроде нормально работает, но учитывая подводный камень с особенностями «самоубийства процесса» правильным сигналом можно и легко налажать. Люди, даже в ряде проектов на гитхабе делали выход просто через sys.exit с нужным кодом, хотя если верить ссылке это шляпа.
Вообще лучше заведи гитхаб и выкладывай туда всё интересное. Наверняка кого-то заинтересует, прямо сейчас мне фильтра не нужен, но как я понял у тебя медианный фильтр для N-мерного пространства? Это чтобы с каналами работать как с пространствами? Меня бы он заинтересовал во времена студенчества, потому что я очень хотел писать диплом про работу с картинками, но в результате писал про работу с деньгами.
ЗЫ
Дамп не очень годится. Там работа с HDD в цикле. Файлы удаляются, перемещаются и так далее, так что ждать конца перемещений всё равно надо. Некоторые штуки между запусками могут меняться из-за того что я ручками новую порцию файлов закину в разгребаемую директорию, например и их при запуске надо проверять, не добавилось ли чего нового. По сути скрипт помойку разгребает у меня на диске, раскладывая файлы по категориям не более того.
У меня есть гитхаб, я его тут просто не показываю;-)
у тебя медианный фильтр для N-мерного пространства?
Да.
Это чтобы с каналами работать как с пространствами?
Э… о таком я не думал, хотя это наверное возможно. Нет, он рассчитан именно на N-мерные картинки. Скажем не из пикселей а из вокселей (хотя 2D тоже могет, и вообще D любое целое положительное число, в разумных пределах конечно;-))
По сути скрипт помойку разгребает у меня на диске, раскладывая файлы по категориям не более того.
Тогда и дамп как таковой не нужен, просто стартуешь из текущего положения помойки?
Может быть полезно в медицине, например для диагностики ковида. Насколько я понимаю КТ/МРТ по слоям картинку делают, так что и в 3D картинку переделать можно.
Тогда и дамп как таковой не нужен, просто стартуешь из текущего положения помойки?
Тоже можно, но захотелось с сигналами повозиться. Тем более, что так можно и журнал перемещений впихнуть и не бояться что что-то улетит не отметившись в нём.