Проблема в том, что исполнитель настаивает на том, чтобы все запущенные фьючерсы были завершены к моменту завершения программы. Но в этом случае вам действительно нужно «нечистое» завершение, потому что нет переносимого способа отмены текущего read()
или асинхронного доступа к sys.stdin
.
Отмена будущего не имеет никакого эффекта, потому что concurrent.futures.Future.cancel
не работает, когда его обратный вызов начал выполняться. Лучший способ избежать нежелательного ожидания - это в первую очередь избегать run_in_executor
и просто создавать собственный поток:
async def ainput():
loop = asyncio.get_event_loop()
fut = loop.create_future()
def _run():
line = sys.stdin.readline()
loop.call_soon_threadsafe(fut.set_result, line)
threading.Thread(target=_run, daemon=True).start()
return await fut
Поток создается вручную и помечается как "демон", поэтому никто не будетдождитесь его при закрытии программы. В результате вариант кода, который использует ainput
вместо run_in_executor(sys.stdin.readline)
, завершается, как и ожидалось:
async def console_input_loop():
while True:
inp = await ainput()
print(f"[{inp.strip()}]")
# rest of the program unchanged