У меня есть служебный класс, который планирует выполнение задания за timeout
секунд:
class AsyncTimer:
def __init__(self, timeout, callback):
self._timeout = timeout
self._callback = callback
self._task = asyncio.ensure_future(self._job())
async def _job(self):
await asyncio.sleep(self._timeout)
await self._callback()
У меня также есть конечный автомат, подобный следующему:
class IState(metaclass=abc.ABCMeta):
def __init__(self, machine):
self._machine = machine
# The OnState can only transition into the TurningOffState, etc...
class OnState(IState):
def __init__(self, machine):
super().__init__(machine)
print("Turned on!")
def turnOff(self):
self.__machine.currentState = TurningOffState(self._machine)
class OffState(IState):
def __init__(self, machine):
super().__init__(machine)
print("Turned off!")
def turnOn(self):
self.__machine.currentState = TurningOnState(self._machine)
# Transition state that has no state transitions. automaticly transitions to `OnState` after 2 secconds
class TurningOnState(IState):
async def _callback(self):
self._machine.currentState = OnState(self._machine)
def __init__(self, machine):
super().__init__(machine)
print("Turning on!")
self.__timer = AsyncTimer(2, self._callback)
У меня есть объект, который содержит текущее активное состояние:
class FSM:
def __init__(self):
self.currentState = OffState(self)
def __del__(self):
print("destroying FSM")
Мой главный l oop выглядит так:
async def main():
fsm = FSM()
fsm.currentState.turnOn()
# fsm gets destroyed here, along with currently contained state which may have a pending task. How do I fix this?
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(main())
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
Это выводит:
Turned Off!
Turning On!
destroying FSM
Task was destroyed but it is pending!
task: <Task pending coro=<AsyncTimer._job() done, defined at pythreadtest.py:11> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f0c1d891258>()]>>
Я почти уверен, что проблема в том, что FSM уничтожается после включения запроса вместе с текущим состоянием, в котором может быть отложенная задача.
Как я могу это исправить? Есть ли что-то, что я мог бы вставить в деструктор, чтобы дождаться завершения всех нерешенных задач? Как я мог это сделать? Есть ли другие проблемы с моим дизайном?
Спасибо
edit
Я попытался добавить sleep
после запроса перехода. Это решает мою проблему, но было бы хорошо, если бы FSM мог атомарно sleep
уничтожить, пока все задачи не будут выполнены.
fsm = DoorFSM()
fsm.currentState.openDoor()
await asyncio.sleep(3)
edit2
Другое решение это сделать task
из AsyncTimer
publi c, а затем выставить это в переходных состояниях. то есть:
def __init__(self, machine):
super().__init__(machine)
print("Turning On")
self.__timer = AsyncTimer(2, self._callback)
self.task = self.__timer.task
Основной l oop может затем дождаться окончания этой задачи до sh с wait
fsm = DoorFSM()
fsm.currentState.openDoor()
await asyncio.wait({fsm.currentState.task})
Но я бы предпочел, если бы я мог поставить это в деструкторе FSM
, но оно не позволит мне подождать в деструкторе.