使用asyncio及时更新一些数据并通过aiohttp呈现?

时间:2016-10-04 16:51:40

标签: python python-asyncio aiohttp

我正在尝试编写一个片段来研究Python asyncio。基本思路是:

  1. 使用"简单" Web服务器(aiohttp)向用户提供一些数据

  2. 返回给用户的数据会立即更改

  3. 这是代码:

    import asyncio
    import random
    from aiohttp import web
    
    userfeed = [] # the data suppose to return to the user via web browsers 
    
    async def data_updater():  #to simulate data change promptly
        while True:
            await asyncio.sleep(3)
            userfeed = [x for x in range(random.randint(1, 20))]
            print('user date updated: ', userfeed)
    
    
    async def web_handle(request):
        text = str(userfeed)
        #print('in handler:', text)  # why text is empty?
        return web.Response(text=text)
    
    async def init(loop):
        app = web.Application(loop=loop)
        app.router.add_route('GET', '/', web_handle)
        srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
        print('Server started @ http://127.0.0.1:8000...')
        return srv
    
    loop = asyncio.get_event_loop()
    asyncio.ensure_future(data_updater())  
    asyncio.ensure_future(init(loop))
    loop.run_forever()
    

    问题是,代码正在运行(python 3.5),但userfeed在浏览器和web_handler()中始终为空: - (

    1. 为什么userfeed没有更新?
    2. 关于这个timely date update函数,因为更新机制可能会更复杂,以后可能会涉及异步IO等待,是否有更好的方法,而不是在while True: await asyncio.sleep(3)中使用data_updater()来获取"更粗略精确"计时器?

1 个答案:

答案 0 :(得分:1)

主要问题是您忘记了global userfeeddata_updater函数中的语句web_handle。因此,根据how python resolves scopes,在web_handle中,它指的是您定义的全局变量,在data_updater中指的是由userfeed = [x for x ...语句创建的本地变量。在此上下文中使用全局变量是显式discouraged所以有一个示例使用dict对象的aiohttp.web.Application接口来安全地引用函数之间的变量。

import asyncio
import random
from aiohttp import web


async def data_updater(app):
    while True:
        await asyncio.sleep(3)
        app["userfeed"] = [x for x in range(random.randint(1, 20))]

async def web_handle(request):
    userfeed = request.app["userfeed"]
    return web.Response(text=str(userfeed))

async def init(loop, port=8000):
    app = web.Application(loop=loop)
    app.router.add_route('GET', '/', web_handle)
    handler = app.make_handler()
    srv = await loop.create_server(
        handler, '127.0.0.1', port=port)
    return srv, app, handler

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    srv, app, handler = loop.run_until_complete(init(loop, 8000))
    app['userfeed'] = []
    asyncio.ensure_future(data_updater(app))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    finally:
        srv.close()
        loop.run_until_complete(srv.wait_closed())
        loop.run_until_complete(app.shutdown())
        loop.run_until_complete(handler.finish_connections(60.0))
        loop.run_until_complete(app.cleanup())
    loop.close()

当您在127.0.0.1:8000上刷新页面时,您应该有一些新的随机数,因为它们每3秒在服务器端更新一次(您可以将print语句放回到data_updater中验证它。)