Issue
I am in trying to write a snippet to study Python asyncio. The basic idea is:
use a "simple" web server (aiohttp) to present some data to user
the data return to user will change promptly
here is the code:
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()
the problem is, the code is running (python 3.5), but the userfeed
is always empty in browsers and also in web_handler()
:-(
- why
userfeed
is not been updated? - regarding this
timely date update
function, because the update mechanism might be more complex later say async IO wait may be involved, is there a better way instead of usingwhile True: await asyncio.sleep(3)
indata_updater()
to get "more roughly precise" timer?
Solution
The main problem is that you forget the statement global userfeed
in both data_updater
and web_handle
functions. So, according to how python resolves scopes, in web_handle
it was referring to the global variable you defined and in data_updater
to a local one, created by the statement userfeed = [x for x ...
. Using global variables in this context is explicitly discouraged so there is an example using the dict
interface of the aiohttp.web.Application
object to safely refer to your variable between the functions.
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()
When you refresh the page on 127.0.0.1:8000
you should have some new random numbers as they are updated every 3 seconds server-side (you can put back the print
statement in data_updater
to verify it).
Answered By - mgc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.