2016-10-04 5 views
2

저는 파이썬 asyncio를 연구하기위한 스 니펫을 작성하려고합니다. 기본적인 아이디어는 다음과 같습니다asyncio를 사용하면 일부 데이터를 적시에 업데이트하고 aiohttp를 통해 표시 할 수 있습니까?

  1. 사용은 "간단한"웹 서버 (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() 

문제는 코드가 실행 중이고 (파이썬 3.5)는 web_handler() :-(에서 또한 브라우저에서 비어 항상

    userfeed가 업데이트되지 않는 이유
  1. ?
  2. 이 기능과 관련하여 업데이트 메커니즘이 더 복잡 할 수 있기 때문에 나중에 비동기 IO 대기가 관련 될 수 있으므로 data_updater()while True: await asyncio.sleep(3)을 사용하는 대신 더 좋은 방법이 있습니까?
+0

아무런 조치없이 페이지를 탐색하는 사용자에게 알림을 보내시겠습니까? 그렇다면, * websocket * 기술을 살펴 봐야한다.이 기술은 꽤 간단한 방법으로'aiohttp'에 구현되어있다. ([examples] (https://github.com/KeepSafe/aiohttp/blob/master/)가있다. examples/web_ws.py)를 소스 코드에 추가하십시오. 그렇지 않으면 함수들 사이에'userfeed' 변수를 전달하기 위해''app' 객체 (http://aiohttp.readthedocs.io/en/stable/faq.html#id3) ('dict' 인터페이스를 제공합니다)를 사용해야합니다 글로벌화를 피하십시오. – mgc

+0

@ mgc, 답장을 보내 주셔서 감사합니다. 나는 데이터가 자동으로 사용자의 브라우저에서 플러시되는 것을 원하지 않는다. 단지 클라이언트 풀 모델만으로도 충분할 수있다. wget과 같은 브라우저 나 툴을 통해 URL을 열면 최신 데이터가 나타날 수있다. 여기에서의 혼란은 전역 변수가 업데이트되지 않은 이유입니다. ('web_handler()'print는 항상 []이지만,'data _updater()'는 변경된 것을 보여줍니다)? 비동기 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'를 가지고 있습니다). – mgc

답변

1

주요 문제는 모두 data_updaterweb_handle 기능에 문 global userfeed를 잊어 버린 것입니다. 따라서 how python resolves scopes에 따르면 은 사용자가 정의한 전역 변수를 참조하고 data_updater은 로컬 변수이고 userfeed = [x for x ... 문으로 작성되었습니다. 이 컨텍스트에서 전역 변수를 사용하는 것은 명시 적으로 discouraged이므로 aiohttp.web.Application 개체의 dict 인터페이스를 사용하여 함수간에 안전하게 변수를 참조하는 예가 있습니다. 당신이 127.0.0.1:8000에서 페이지를 새로 고침 할 때 그들은 매 3 초마다 서버 측 업데이트로

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() 

당신이 몇 가지 새로운 난수를해야한다 (당신은 그것을 확인하기 위해 data_updaterprint 문을 다시 넣을 수 있습니다).

+0

나는 어리석은 abc 실수를 한 것 같다 : (당신의 상세한 설명에 대한 많은 감사, 정말 감사합니다 – user340307

+0

도움이 되니 기쁩니다! – mgc