How to not await in a loop with asyncio?
Here is a toy example that downloads the home page from several websites using asyncio and aiohttp:
import asyncio
import aiohttp
sites = [
"http://google.com",
"http://reddit.com",
"http://wikipedia.com",
"http://afpy.org",
"http://httpbin.org",
"http://stackoverflow.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()
If I run it, I get:
RuntimeWarning: coroutine 'download' was never awaited
But I don't want to await it.
In twisted I can do:
for site in sites:
download(site)
And If I don't explicitly "yield" or add a callback to the returned Deferred, it just runs without blocking nor complaining. I can't access the result, but in this case I don't need it.
In JS I can do:
site.forEarch(site){
donwload(site)
}
And again, it doesn't block nor does it requires anything from my part.
I found a way to do:
async def main(sites):
await asyncio.wait([download(site) for site in sites])
But:
It there a better way ?
The documentation on coroutines does make it pretty clear what asyncio.wait
's purpose is.
Again, see the documentation.
Again, see the documentation, specifically asyncio.as_completed
It should still work.
Then you can use asyncio.ensure_furture
. In fact, asyncio.wait
is a convenience function around asyncio.ensure_future
(and some other logic).
Maybe, but that's not a bad thing (from my perspective).
In order to schedule a coroutine as a task, use asyncio.ensure_future:
for site in sites:
coro = download(site)
future = asyncio.ensure_future(coro)
It replaces the deprecated function asyncio.async in version 3.4.4.
Then you can manage those futures using await
, asyncio.wait or asyncio.gather.
上一篇: Asyncio协程
下一篇: 如何不等待与asyncio循环?