asyncio + aiohttp:为什么我的客户端仍然阻塞?

时间:2018-01-30 00:13:52

标签: python python-asyncio aiohttp

我试图测试我的python 3.4.3 http客户端或将HTTP请求发送到服务器的应用程序。如果服务器由于某种原因而有延迟响应,我希望请求不应该阻塞,因为asyncio + aiohttp应该提供异步调用:

def post(self):
    print("received post")
    print(self.request)
    print("POST Body: %s" % str(self.request.body))
    time.sleep(3)
    self.write("blah")
    self.finish()

我只是想知道为什么我的代码/ http客户端阻塞了:

import aiohttp, asyncio, async_timeout

@asyncio.coroutine
def fetch(session, url):
    with aiohttp.Timeout(30):
        try:
            response = yield from session.get(url)
            print((yield from response.read()))
            return response
        except Exception as e:
            raise e
        finally:
            try:
                response.release()
            except:
                pass

@asyncio.coroutine
def post(session, url):
    with aiohttp.Timeout(30):
        try:
            response = yield from session.post(url)
            print((yield from response.read()))
            return response
        except Exception as e:
            raise e
        finally:
            try:
                response.release()
            except:
                pass

@asyncio.coroutine
def close_connection(session):
    try:
        session.close()
    except:
        pass

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession(loop=loop)
    try:
        for i in range(10):
            html = loop.run_until_complete(post(session, 'http://localhost:8000'))
    except Exception as e:
        print("received exception %s." % type(e).__name__)

        # Close session if not closed.
    loop.run_until_complete(close_connection(session))

我尝试做一个循环,我遍历10个URL(这里是相同的一个)。如果它是顺序的,我希望它需要约30秒(服务器响应3秒延迟)。对于异步,我的期望是它需要更少。

try:
    for i in range(10):
        html = loop.run_until_complete(post(session, 'http://localhost:8000'))

是" run_until_complete()"阻塞的功能?如何使其无阻塞?

1 个答案:

答案 0 :(得分:3)

基本上,当你使用run_until_complete()时,你告诉事件循环运行作为参数传递的协同程序并在完成时返回结果。简而言之,run_until_complete()将阻塞,直到完成该操作。

基于您的for循环代码段。基本上在每个循环中,run_until_complete将阻塞,在此上下文中运行协程(post),返回结果,然后只有下一个循环才会继续执行。

您要在此处执行的操作是同时运行所有post。你可以做的是使用asyncio.gather()

try:
    html = loop.run_until_complete(asyncio.gather(*[post(session, 'http://localhost:8000') for i in range(10)]))