2016-10-04 8 views
2

Я пытаюсь написать фрагмент, чтобы изучить Python 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), но userfeed всегда пусто в браузерах, а также в web_handler() :-(

  1. почему userfeed не был обновлен?
  2. относительно этого timely date update функция, потому что механизм обновления может быть более сложным позже сказать, что асинхронный запрос ожидания может быть задействован, есть ли лучший способ вместо того, чтобы использовать while True: await asyncio.sleep(3) в data_updater(), чтобы получить «более точный» таймер?
+0

Вы хотите получать уведомления пользователю, просматривающему вашу страницу (без каких-либо действий от него)? Если это так, вы должны взглянуть на технологию * websocket *, она реализована в 'aiohttp' довольно простым способом (есть [примеры] (https://github.com/KeepSafe/aiohttp/blob/master/ примеры/web_ws.py) в исходном коде). В противном случае вы должны использовать свой объект '' app' (http://aiohttp.readthedocs.io/en/stable/faq.html#id3) (который предоставляет интерфейс 'dict') для передачи переменной' userfeed' между функциями и избегать его глобального. – mgc

+0

@ mgc, спасибо, что ответили. Я не хочу, чтобы данные автоматически очищались в браузере пользователя, просто модель клиентского тяги могла бы быть достаточной - каждый раз, когда вы открываете URL-адрес через браузер или инструмент вроде wget, могут появляться последние данные. Путаница здесь в том, почему глобальная переменная не обновлялась (внутри 'web_handler()' print показывает, что она всегда [], но 'data_updater()' печатать изменено)? async def отличается от обычного def, он каким-то образом кэширует контекст? – user340307

+0

См. Мой ответ для примера, так как использование глобальной переменной в этом контексте явно обескураживается [документацией] (http://aiohttp.readthedocs.io/en/stable/web.html#data-sharing-aka-no- одиночки-пожалуйста). Но если вам действительно нужно заставить его работать с помощью глобального 'userfeed', просто добавьте' global userfeed' в функции 'data_updated' и' web_handle', и он должен работать (таким образом функция знает, что 'userfeed' относится к переменной расположенный в глобальном масштабе, в вашем примере каждая функция имела свой собственный локальный 'userfeed'). – mgc

ответ

1

Основная проблема заключается в том, что вы забыли о global userfeed в обоих data_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 проверить его).

+0

Кажется, я сделал глупую ошибку abc :(Большое спасибо за ваше подробное объяснение, очень оценили – user340307

+0

Рад, что это помогло! – mgc

 Смежные вопросы

  • Нет связанных вопросов^_^