sockets - python asyncio run event loop once? -
i trying understand asyncio library, using sockets. have written code in attempt gain understanding,
i wanted run sender , receiver sockets asynchrounously. got point data sent till last one, have run 1 more loop. looking @ how this, found this link stackoverflow, implemented below -- going on here? there better/more sane way call stop
followed run_forever
?
the documentation stop()
in event loop is:
stop running event loop.
every callback scheduled before stop() called run. callbacks scheduled after stop() called not run. however, callbacks run if run_forever() called again later.
and run_forever()
's documentation is:
run until stop() called.
questions:
- why in world
run_forever
wayrun_once
? doesn't make sense - is there better way this?
- does code reasonable way program asyncio library?
- is there better way add tasks event loop besides
asyncio.async()
?loop.create_task
gives error on linux system.
https://gist.github.com/cloudformdesign/b30e0860497f19bd6596
the stop(); run_forever()
trick works because of how stop
implemented:
def stop(self): """stop running event loop. every callback scheduled before stop() called run. callback scheduled after stop() called won't. however, callbacks run if run() called again later. """ self.call_soon(_raise_stop_error) def _raise_stop_error(*args): raise _stoperror
so, next time event loop runs , executes pending callbacks, it's going call _raise_stop_error
, raises _stoperror
. run_forever
loop break on specific exception:
def run_forever(self): """run until stop() called.""" if self._running: raise runtimeerror('event loop running.') self._running = true try: while true: try: self._run_once() except _stoperror: break finally: self._running = false
so, scheduling stop()
, calling run_forever
, end running 1 iteration of event loop, stopping once hits _raise_stop_error
callback. may have noticed _run_once
defined , called run_forever
. call directly, can block if there aren't callbacks ready run, may not desirable. don't think there's cleaner way - answer provided andrew svetlov, asyncio
contributor; know if there's better option. :)
in general, code looks reasonable, though think shouldn't using run_once
approach begin with. it's not deterministic; if had longer list or slower system, might require more 2 iterations print everything. instead, should send sentinel tells receiver shut down, , wait on both send , receive coroutines finish:
import sys import time import socket import asyncio addr = ('127.0.0.1', 1064) sentinel = b"_done_" # ... (this stuff same) @asyncio.coroutine def sending(addr, dataiter): loop = asyncio.get_event_loop() d in dataiter: print("sending:", d) sock = socket.socket() yield send_close(loop, sock, addr, str(d).encode()) # send sentinel sock = socket.socket() yield send_close(loop, sock, addr, sentinel) @asyncio.coroutine def receiving(addr): loop = asyncio.get_event_loop() sock = socket.socket() try: sock.setblocking(false) sock.bind(addr) sock.listen(5) while true: data = yield accept_recv(loop, sock) if data == sentinel: # got sentinel return print("recevied:", data) finally: sock.close() def main(): loop = asyncio.get_event_loop() # add these items event loop recv = asyncio.async(receiving(addr), loop=loop) send = asyncio.async(sending(addr, range(10)), loop=loop) loop.run_until_complete(asyncio.wait([recv, send])) main()
finally, asyncio.async
right way add tasks event loop. create_task
added in python 3.4.2, if have earlier version won't exist.
Comments
Post a Comment