可以取消的异步键盘输入

2024-04-26 09:16:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用asyncio编写一个同时接受键盘输入的并发Python程序。当我试图关闭程序时,问题出现了。因为键盘输入最后是用sys.stdin.readline完成的,所以该函数只在我按ENTER之后返回,而不管我是stop()事件循环还是cancel()函数的Future。你知道吗

有没有什么方法可以提供可以取消的asyncio键盘输入?你知道吗

这是我的MWE。它将接受键盘输入1秒,然后stop()

import asyncio
import sys

async def console_input_loop():
    while True:
        inp = await loop.run_in_executor(None, sys.stdin.readline)
        print(f"[{inp.strip()}]")

async def sleeper():
    await asyncio.sleep(1)
    print("stop")
    loop.stop()

loop = asyncio.get_event_loop()
loop.create_task(console_input_loop())
loop.create_task(sleeper())
loop.run_forever()

Tags: 函数importloopasyncioinputreadlineasyncdef
1条回答
网友
1楼 · 发布于 2024-04-26 09:16:17

问题是,执行者坚持要确保在程序终止时所有正在运行的期货都已完成。但在这种情况下,您实际上需要一个“不干净”的终止,因为没有可移植的方法来取消正在进行的read()或异步访问sys.stdin。你知道吗

取消future没有任何效果,因为^{}一旦开始执行回调,它就是一个no-op。避免不必要的等待的最佳方法是首先避免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

线程是手动创建的,并标记为“daemon”,因此在程序关闭时没有人会等待它。因此,使用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

相关问题 更多 >