如何在不阻塞的情况下发出请求(使用asyncio)?

时间:2017-10-11 16:50:38

标签: python python-3.x python-requests python-asyncio

我想使用asyncio

来实现以下目标
# Each iteration of this loop MUST last only 1 second
while True:
    # Make an async request

    sleep(1)

然而,我见过的唯一例子使用了

的一些变体
async def my_func():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, requests.get, 'http://www.google.com')

loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())

但是run_until_complete正在阻止!在run_until_complete循环的每次迭代中使用while将导致循环阻塞。

我花了最后几个小时试图弄清楚如何正确运行非阻塞任务(使用async def定义)但没有成功。我必须遗漏一些明显的东西,因为这样简单的东西肯定会很简单。我怎样才能实现我所描述的目标?

1 个答案:

答案 0 :(得分:0)

run_until_complete运行主事件循环。它没有"阻止"可以这么说,它只运行事件循环,直到您作为参数返回的协程返回。它必须挂起,否则程序将停止或被下一条指令阻止。

很难说出你愿意实现的目标,但这段代码实际上有所作为:

async def my_func():
    loop = asyncio.get_event_loop()
    while True:
        res = await loop.run_in_executor(None, requests.get, 'http://www.google.com')
        print(res)
        await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(my_func())

它会每秒在Google主页上执行GET请求,弹出一个新线程来执行每个请求。您可以通过虚拟并行运行多个请求来说服自己,它实际上是非阻塞的:

async def entrypoint():
    await asyncio.wait([
        get('https://www.google.com'),
        get('https://www.stackoverflow.com'),
    ])

async def get(url):
    loop = asyncio.get_event_loop()
    while True:
        res = await loop.run_in_executor(None, requests.get, url)
        print(url, res)
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(entrypoint())

另一件需要注意的事情是,您每次都在不同的线程中运行请求。它有效,但它有点像黑客。您应该使用真正的异步HTTP客户端,例如aiohttp