python - 可以取消的异步键盘输入
问题描述
我正在尝试使用它编写一个并发 Python 程序asyncio
,它也接受键盘输入。当我尝试关闭我的程序时出现问题。由于键盘输入最终完成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()
解决方案
问题是执行者坚持要确保在程序终止时所有正在运行的期货都已完成。但在这种情况下,您实际上想要一个“不干净”的终止,因为没有可移植的方式来取消正在进行的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
推荐阅读
- dynamics-crm - 队列项目拾取和释放按钮
- android - 我的代码显示错误的哪个原因:禁止?
- web - 设备检测逻辑放在哪里?后端还是前端?
- c++ - 如何用 SSE 实现卷积算法?
- sql - 如何从 start_date 到 end_date SQL 进行成本分析?
- html - z-index 无法在 HTML5 视频的全屏模式下工作
- django - 在 drf 的一个项目中,我有端点“api/v1/invoice/#id/”,所以我想授予查看此发票的唯一作者的权限
- android - 如何使双击以在 Android WebView 中转发 youtube 嵌入视频?
- python - 驱动成本 - python 中的函数 - if __name__ == '__main__' 中的 EOFerror:
- airflow - 了解 poke_interval 和 timeout 如何与 Airflow 中的 schedule_interval 一起使用