如何不等待异步循环?
How to not await in a loop with asyncio?
这是一个玩具示例,使用 asyncio 和 aiohttp 从多个网站下载主页:
import asyncio
import aiohttp
sites = [
"http://google.com",
"http://reddit.com",
"http://wikipedia.com",
"http://afpy.org",
"http://httpbin.org",
"http://whosebug.com",
"http://reddit.com"
]
async def main(sites):
for site in sites:
download(site)
async def download(site):
response = await client.get(site)
content = await response.read()
print(site, len(content))
loop = asyncio.get_event_loop()
client = aiohttp.ClientSession(loop=loop)
content = loop.run_until_complete(main(sites))
client.close()
如果我 运行 它,我得到:
RuntimeWarning: coroutine 'download' was never awaited
但我不想等待。
在twisted中我能做到:
for site in sites:
download(site)
并且如果我没有明确地 "yield" 或向返回的 Deferred 添加回调,它只是 运行s 而不会阻塞或抱怨。我无法访问结果,但在这种情况下我不需要它。
在 JS 中我可以做到:
site.forEarch(site){
donwload(site)
}
同样,它不会阻止也不需要我做任何事情。
我找到了一种方法:
async def main(sites):
await asyncio.wait([download(site) for site in sites])
但是:
- 这个还真是不明显能查出来。我好难记。
- 很难理解它的作用。 "waits" 似乎是说 "i block",但没有明确表达它阻塞了整个协程列表的完成。
- 你不能传入一个生成器,它需要是一个真实的列表,我在Python中感觉很不自然。
- 如果我只有一个可等待怎么办?
- 如果我根本不想等待我的任务,只是安排它们执行然后继续我的其余代码怎么办?
- 它比 twisted 和 JS 解决方案更冗长。
有更好的方法吗?
为了将协程安排为任务,使用asyncio.ensure_future:
for site in sites:
coro = download(site)
future = asyncio.ensure_future(coro)
它取代了版本 3.4.4 中已弃用的函数 asyncio.async。
然后您可以使用 await
、asyncio.wait or asyncio.gather.
管理这些期货
- this is really not obvious to find it out. I it's hard to remember.
关于 coroutines does make it pretty clear what asyncio.wait
目的的文档是。
- it's hard to understand what it does. "waits" seems to say "i block", but does not convey clearly it block for the entire list of coroutine to finish.
同样,请参阅文档。
- you can't pass in a generator, it needs to be a real list, which i feels really unatural in Python.
同样,请参阅文档,特别是 asyncio.as_completed
- what if I have only ONE awaitable ?
它应该仍然有效。
- what if I don't want to wait at all on my tasks, and just schedule them for execution then carry on with the rest of my code ?
那你就可以使用asyncio.ensure_furture
了。事实上,asyncio.wait
是围绕 asyncio.ensure_future
(和其他一些逻辑)的 便利 函数。
- it's way more verbose thant twisted and JS solution.
也许吧,但这不是坏事(从我的角度来看)。
这是一个玩具示例,使用 asyncio 和 aiohttp 从多个网站下载主页:
import asyncio
import aiohttp
sites = [
"http://google.com",
"http://reddit.com",
"http://wikipedia.com",
"http://afpy.org",
"http://httpbin.org",
"http://whosebug.com",
"http://reddit.com"
]
async def main(sites):
for site in sites:
download(site)
async def download(site):
response = await client.get(site)
content = await response.read()
print(site, len(content))
loop = asyncio.get_event_loop()
client = aiohttp.ClientSession(loop=loop)
content = loop.run_until_complete(main(sites))
client.close()
如果我 运行 它,我得到:
RuntimeWarning: coroutine 'download' was never awaited
但我不想等待。
在twisted中我能做到:
for site in sites:
download(site)
并且如果我没有明确地 "yield" 或向返回的 Deferred 添加回调,它只是 运行s 而不会阻塞或抱怨。我无法访问结果,但在这种情况下我不需要它。
在 JS 中我可以做到:
site.forEarch(site){
donwload(site)
}
同样,它不会阻止也不需要我做任何事情。
我找到了一种方法:
async def main(sites):
await asyncio.wait([download(site) for site in sites])
但是:
- 这个还真是不明显能查出来。我好难记。
- 很难理解它的作用。 "waits" 似乎是说 "i block",但没有明确表达它阻塞了整个协程列表的完成。
- 你不能传入一个生成器,它需要是一个真实的列表,我在Python中感觉很不自然。
- 如果我只有一个可等待怎么办?
- 如果我根本不想等待我的任务,只是安排它们执行然后继续我的其余代码怎么办?
- 它比 twisted 和 JS 解决方案更冗长。
有更好的方法吗?
为了将协程安排为任务,使用asyncio.ensure_future:
for site in sites:
coro = download(site)
future = asyncio.ensure_future(coro)
它取代了版本 3.4.4 中已弃用的函数 asyncio.async。
然后您可以使用 await
、asyncio.wait or asyncio.gather.
- this is really not obvious to find it out. I it's hard to remember.
关于 coroutines does make it pretty clear what asyncio.wait
目的的文档是。
- it's hard to understand what it does. "waits" seems to say "i block", but does not convey clearly it block for the entire list of coroutine to finish.
同样,请参阅文档。
- you can't pass in a generator, it needs to be a real list, which i feels really unatural in Python.
同样,请参阅文档,特别是 asyncio.as_completed
- what if I have only ONE awaitable ?
它应该仍然有效。
- what if I don't want to wait at all on my tasks, and just schedule them for execution then carry on with the rest of my code ?
那你就可以使用asyncio.ensure_furture
了。事实上,asyncio.wait
是围绕 asyncio.ensure_future
(和其他一些逻辑)的 便利 函数。
- it's way more verbose thant twisted and JS solution.
也许吧,但这不是坏事(从我的角度来看)。