Python 异步后如何清理。等待';暂停?

Python 异步后如何清理。等待';暂停?,python,python-3.x,python-asyncio,Python,Python 3.x,Python Asyncio,我的目标是练习使用asyncio库。我已经阅读了一些入门教程,现在我想自己写一些代码 我想开始两个简单的任务,它们基本上增加了类外存储的公共值。第一种是5秒后自动增加1。第二个任务与用户相关:如果您在这5秒内输入了一些值,那么也应该添加它 问题是,当我没有输入任何值时,我的循环不会关闭-程序仍然处于活动状态并永远运行,直到我强制停止它-然后我得到以下错误: 2.py [Auto_increment: ] This task will increment value after 5 seconds

我的目标是练习使用asyncio库。我已经阅读了一些入门教程,现在我想自己写一些代码

我想开始两个简单的任务,它们基本上增加了类外存储的公共值。第一种是5秒后自动增加1。第二个任务与用户相关:如果您在这5秒内输入了一些值,那么也应该添加它

问题是,当我没有输入任何值时,我的循环不会关闭-程序仍然处于活动状态并永远运行,直到我强制停止它-然后我得到以下错误:

2.py
[Auto_increment: ] This task will increment value after 5 seconds
[Manual increment: ] Waiting 5s for inc value:
Timeout
Loop finished. Value is 1
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/lib/python3.7/concurrent/futures/thread.py", line 40, in _python_exit
    t.join()
  File "/usr/lib/python3.7/threading.py", line 1032, in join
    self._wait_for_tstate_lock()
  File "/usr/lib/python3.7/threading.py", line 1048, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt

Process finished with exit code 0
基本上,在“循环完成”之后,程序就结束了,但当控制台输入中并没有输入值时,程序就挂起了。当我输入任何v

2.py
[Auto_increment: ] This task will increment value after 5 seconds
[Manual increment: ] Waiting 5s for inc value:
5
Loop finished. Value is 6

Process finished with exit code 0
看起来,当TimeoutError发生时,asyncio.wait_等待后会出现一些未清理的内容。你能帮我告诉我,怎么了?这是我的代码:

import asyncio
import sys


class ValContainer:
    _val = 0

    @staticmethod
    def inc_val(how_many=1):
        ValContainer._val += how_many

    @staticmethod
    def get_val() -> int:
        return ValContainer._val


async def auto_increment():
    print(f'[Auto_increment: ] This task will increment value after 5 seconds')
    await asyncio.sleep(5)
    ValContainer.inc_val()
    return True


async def manual_increment(loop):
    print(f'[Manual increment: ] Waiting 5s for inc value:')
    try:
        future = loop.run_in_executor(None, sys.stdin.readline)
        line = await asyncio.wait_for(future, 5, loop=loop)
        if line:
            try:
                how_many = int(line)
                ValContainer.inc_val(how_many)
            except ValueError:
                print('That\'s not a number!')

    except asyncio.TimeoutError:
        print('Timeout')
    finally:
        return True

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    task_auto = loop.create_task(auto_increment())
    task_man = loop.create_task(manual_increment(loop))
    loop.run_until_complete(task_auto)
    loop.run_until_complete(task_man)
    print(f'Loop finished. Value is {ValContainer.get_val()}')
    loop.close()

您已经在threadpoolexecutor中启动了一个单独的线程。任务
asyncio
'delegate'被取消,但是
sys.stdin.readline
调用将无限期地停留在那里。您可以通过按enter键结束它,因为这将在
sys.stdin
上为您提供完整的一行

你必须在这里使用;请注意,您不能告诉
ThreadPoolExecutor
使用守护进程线程


在异步IO上下文中作为单独任务等待用户输入的情况下,创建自己的线程可能比让
THreadPoolExecutor
为您管理线程更容易,因此,您可以在该线程上设置
daemon=True
,然后让进程在退出时杀死该线程。

不确定在递增类值时为什么使用静态方法。如果您希望该类是一个名称空间的全局类,那么至少您自己可以更轻松地使用
@classmethod
@RomanPerekhrest:这取决于操作系统。你的进程真的退出了吗?还是在退出之前你必须按enter键?@MartijnPieters,这就是问题的模糊性——“异步IO之后有东西没有清理。等等”@Asmox,你需要退出整个程序还是确保事件循环已关闭?@RomanPerekhrest:事件循环已关闭,他们在问为什么他们的流程没有退出。如果循环没有关闭,您就不会完成
循环。值为1
输出。可以考虑另一种解决方法来取消整个“使用ThreadPoolExecutor在执行器中运行”。()不仅仅是
sys.stdin
@RomanPerekhrest:不,这也不会起作用,正如该要点中所述:关机是为了阻止新的工作进入,而不是停止已经存在的工作。这一要点使用了
sleep()
s调用,该调用最终会自行退出。@RomanPerekhrest:您得到的只是线程上没有
join()
调用。进程仍将在线程上等待,直到您发出中断。我觉得我不喜欢
run\u in\u executor这样的事实(
是如此难以管理,导致了这样的解决方法。我会选择一个单独的线程/进程,它可以被识别/杀死,@RomanPerekhrest这不限于
ThreadPoolExecutor
,这是线程的问题,完全停止。一个单独的进程也有限制,然后你需要担心分离流。