run - import async python
E/S sin bloqueo con asyncio (3)
Estoy tratando de escribir un juego en red con Pygame y asyncio, pero no puedo averiguar cómo evitar colgar en las lecturas. Aquí está mi código para el cliente:
@asyncio.coroutine
def handle_client():
print("Connected!")
reader, writer = yield from asyncio.open_connection(''localhost'', 8000)
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
mouse_up = True
if mouse_up:
print("Writing")
writer.write(b"Mouse up")
print("Waiting to read")
line = yield from reader.read(2**12)
print(line.decode())
writer.close()
Esto cuelga en la línea line = yield from reader.read(2**12)
. Anteriormente pensé que el punto de asyncio era que no era de bloqueo, por lo que si no hubiera datos para leer, simplemente continuaría ejecutándose. Ahora veo que este no es el caso.
¿Cómo integro el código de red de asyncio con el código de evento y dibujo de Pygame?
Bueno, ya que está intentando leer el valor de ''línea'' justo después de llamar a read (), necesita ese valor a cualquier costo ...
si la rutina no se detendría porque no hay datos, podría obtener un AttributeError en la llamada line.decode () si ''line'' es None.
una cosa que puede hacer es establecer un tiempo de espera en la llamada de bloqueo y manejar la excepción de tiempo de espera:
...
print("Waiting to read")
try: # block at most for one second
line = yield from asyncio.wait_for(reader.read(2**12), 1)
except asyncio.TimeoutError:
continue
else:
print(line.decode())
...
El punto de yield from
es cambiar la ejecución al bucle de eventos de asyncio y bloquear la rutina actual hasta que el resultado esté disponible. Para programar una tarea sin bloquear la rutina actual, puede usar asyncio.async()
.
Para imprimir datos de lectura hasta el momento sin bloquear el bucle de pygame:
@asyncio.coroutine
def read(reader, callback):
while True:
data = yield from reader.read(2**12)
if not data: # EOF
break
callback(data)
@asyncio.coroutine
def echo_client():
reader, ...
chunks = []
asyncio.async(read(reader, chunks.append))
while True:
pygame.event.pump() # advance pygame event loop
...
if chunks: # print read-so-far data
print(b''''.join(chunks).decode())
del chunks[:]
yield from asyncio.sleep(0.016) # advance asyncio loop
No debe haber llamadas de bloqueo dentro del bucle while.
read()
y sleep()
coroutines se ejecutan simultáneamente en el mismo hilo (obviamente, también se pueden ejecutar otras coroutines al mismo tiempo).
Puede "transformar" una tarea de bloqueo en una no-bloqueo.
Sugiero esto: https://docs.python.org/3/library/asyncio-eventloop.html#executor .
Tengo una función que escucha un feed de Twitter, la función "mención", y la ejecuto en un ejecutor, por lo que si se bloquea, no bloquea las otras tareas.
@asyncio.coroutine
def boucle_deux():
#faire attendre la boucle si pas bcp de mots
while True:
print("debut du deux")
value = t.next()
future2 = loop.run_in_executor(None, mention, "LQNyL2xvt9OQMvje7jryaHkN8",
"IRJX6S17K44t8oiVGCjrj6XCVKqGSX9ClfpGpfC467rajqePGb",
"2693346740-km3Ufby8r9BbYpyzcqwiHhss22h4YkmnPN4LnLM",
"53R8GAAncFJ1aHA1yJe1OICfjqUbqwcMR38wSqvbzsQMB", 23, value)
response2 = yield from future2
yield from asyncio.sleep(5)
print("fin du deux")
asyncio.Task(boucle_deux())