2016-10-04 27 views
2

我试图写一段代码来学习Python asyncio。其基本思想是:使用asyncio更新一些数据及时通过aiohttp呈现?

  1. 使用“简单的” Web服务器(aiohttp)一些数据呈现给用户

  2. 数据返回给用户将会改变及时

这里代码:

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()来得到“更精确”的定时器?
+0

你想推动通知浏览你的网页的用户(没有任何他的行动)?如果是这样,你应该看看* websocket *技术,它在'aiohttp'中以一种非常简单的方式实现(有[示例](https://github.com/KeepSafe/aiohttp/blob/master/ examples/web_ws.py)在源代码中)。否则,你应该使用你的['app'对象](http://aiohttp.readthedocs.io/en/stable/faq.html#id3)(它提供了一个'dict'接口)来在函数之间传递'userfeed'变量并避免使其成为全球性的。 – mgc

+0

@ mgc,谢谢你的回复。我不希望数据在用户的浏览器中自动刷新,只需一个客户端拉模型就足够了 - 每当用户通过浏览器或wget等工具打开URL时,最新的数据就会显示出来。这里的混淆是,为什么全局变量没有被更新(在'web_handler()'print内部显示它总是[],但是'data _updater()'打印它会改变)? async def与普通def不同,它会以某种方式缓存上下文吗? – user340307

+0

查看我的答案的一个示例,因为在此上下文中使用全局变量明显不鼓励[documentation](http://aiohttp.readthedocs.io/en/stable/web.html#data-sharing-aka-no-单身-请)。但是,如果你真的需要使用全局'userfeed'来工作,只需在'data_updated'和'web_handle'函数中添加'global userfeed',它就可以工作(这样函数就知道'userfeed'指向一个变量位于全局范围内,在您的示例中,每个函数都有自己的本地'userfeed')。 – mgc

回答

1

主要的问题是,你忘了声明global userfeed两个data_updaterweb_handle功能。因此,根据how python resolves scopes,在web_handle中指的是您定义的全局变量,并且data_updater指的是由语句userfeed = [x for x ...创建的本地变量。在这种情况下使用全局变量显式为discouraged,因此有一个示例使用aiohttp.web.Application对象的接口dict来安全地引用函数之间的变量。

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进行验证)。

+0

似乎我犯了一个愚蠢的ABC错误:(非常感谢您的详细解释,真的很感谢 – user340307

+0

很高兴帮助! – mgc

相关问题