Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python异步IO动态添加任务_Python_Python Asyncio - Fatal编程技术网

python异步IO动态添加任务

python异步IO动态添加任务,python,python-asyncio,Python,Python Asyncio,我正在学习python中的asyncio,我想尝试使用asyncio。我的目标是不断地从用户处读取输入,并使用该输入创建需要异步运行的作业/任务 import asyncio import os loop = asyncio.get_event_loop() async def action(): inp = int(input('enter: ')) await asyncio.sleep(inp) os.system(f"say '{inp} second

我正在学习python中的asyncio,我想尝试使用asyncio。我的目标是不断地从用户处读取输入,并使用该输入创建需要异步运行的作业/任务

import asyncio
import os
loop = asyncio.get_event_loop()

async def action():
    inp = int(input('enter: '))
    await asyncio.sleep(inp)
    os.system(f"say '{inp} seconds waited'")

async def main():
    while True:
        await asyncio.ensure_future(action())

try:
    asyncio.run(main())
except Exception as e:
    print(str(e))
finally:
    loop.close()

我把事情搞砸了,我想知道如何实现它。每次用户输入一个数字,脚本都需要在给定的时间内休眠,然后说出它已经等待了。整个事情需要同时进行。如果用户输入100作为输入,脚本应该启动一个任务以休眠100秒,但在用户端,它需要在用户输入后再次请求输入。

代码的主要问题是您直接在异步函数中调用了
input()
<代码>输入本身是一个阻塞函数,在读取换行符或文件结尾之前不会返回。这是一个问题,因为Python异步代码仍然是单线程的,如果有一个阻塞函数,则不会执行其他任何操作。在这种情况下,您需要使用

代码的另一个问题(尽管与您的问题没有直接关系)是,您混合了python3.7之前调用事件循环的方式和python3.7+方式。根据,
asyncio.run
单独使用。如果您想使用3.7之前的方法调用循环,正确的方法是

loop=asyncio.get\u event\u loop()
循环。运行\u直到完成(main())

loop=asyncio.get\u event\u loop()
asyncio.sure_future(main())
loop.run_forever()
由于在
main()
中有一个
while True
,所以
在完成之前运行与
永远运行之间没有区别

最后,在
main()
中使用
sure\u future()
没有任何意义。
sure_future
的要点是提供一个“正常”(即非异步)函数,将事情安排到事件循环中,因为它们不能使用
wait
关键字。使用“确保未来”的另一个原因是,如果您希望在不等待结果的情况下安排许多具有高io界限(例如网络请求)的任务,则可以使用“确保未来”。由于您正在等待函数调用,因此使用
确保未来
自然没有意义

以下是修改后的版本:

导入异步IO
导入操作系统
异步定义操作():
loop=asyncio.get\u running\u loop()
inp=等待循环。在执行器中运行(无,输入‘输入一个数字:’)
等待异步睡眠(int(inp))
系统(f“说{inp}秒等待’)
异步def main():
尽管如此:
等待行动
asyncio.run(main())
在此版本中,在输入用户输入之前,代码执行在
await action()
await循环之间交替进行。在执行器()中运行。当没有安排其他任务时,事件循环大部分处于空闲状态。但是,当有计划的事情发生时(使用
wait sleep()
模拟),控制权将自然转移到计划的长时间运行的任务


Python异步编程的一个关键是,您必须确保偶尔将控件传输回事件循环,以便可以运行其他计划的事情。每当遇到
wait
时,就会发生这种情况。在您的原始代码中,解释器被困在
input()
,从未有机会返回到事件循环,这就是为什么在提供用户输入之前,不会执行任何其他计划任务的原因。

您可以尝试以下方法:

import asyncio


WORKERS = 10


async def worker(q):
    while True:
        t = await q.get()
        await asyncio.sleep(t)
        q.task_done()

        print(f"say '{t} seconds waited'")


async def main():
    q = asyncio.Queue()

    tasks = []

    for _ in range(WORKERS):
        tasks.append(asyncio.create_task(worker(q)))

    print(f'Keep inserting numbers, "q" to quit...')

    while (number := await asyncio.to_thread(input)) != "q":
        q.put_nowait(int(number))

    await q.join()

    for task in tasks:
        task.cancel()

    await asyncio.gather(*tasks, return_exceptions=True)


if __name__ == "__main__":
    asyncio.run(main())
测试:

$ python test.py
Keep inserting numbers, "q" to quit...
1
say '1 seconds waited'
3
2
1
say '1 seconds waited'
say '2 seconds waited'
say '3 seconds waited'
q

注意:由于使用了一些新语法(
:=
)和函数(
asyncio.to_thread
),需要Python 3.9+

感谢您的回答。那么,我想用asyncio实现我的目标,这是不可能的吗?@AjayDyavathi这是可能的,我相信我发布的修改版本正是你所要求的。也许我误解了你的问题?