2016-10-04 56 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

相關問題