Timeout para python coroutines

¿Cómo puedo hacer una parada de coroutine con timeout?

No entiendo por qué asyncio.wait_for () no funciona para mí. Tengo tanta tranquilidad de código (planeando hacer mi implementación de cliente telnet):

def expect(self, pattern, timeout=20): if type(pattern) == str: pattern = pattern.encode('ascii', 'ignore') return self.loop.run_until_complete(asyncio.wait_for(self.asyncxpect(pattern), timeout)) async def asyncxpect(self, pattern): #receives data in a cumulative way until match is found regexp = re.compile(b'(?P[\s\S]*)(?P%s)' %pattern) self.buffer = b'' while True: # add timeout # add exception handling for unexpectedly closed connections data = await self.loop.sock_recv(self.sock, 10000) self.buffer += data m = re.match(regexp, self.buffer) if m: payload = m.group('payload') match = m.group('pattern') return payload, match 

Como pensé en este código, en algún momento (en la instrucción de espera) se devuelve el control al bucle de eventos. Pensé que debería suceder cuando no hay más datos para recibir. Y si el bucle de eventos tiene control, puede detenerse con el tiempo de espera.

Pero si el servidor no envía nada útil (que coincida), mi código simplemente tropieza en este bucle, justo en el punto de espera.

Creo que es diferente de este problema. Python asyncio force timeout , porque no estoy usando instrucciones de locking como time.sleep (n).

    Aqui esta mi codigo

    Cuando el servidor cierra la conexión, sock_recv devuelve un bytearray vacío ( b'' ), que indica el final del archivo. Como no maneja esa condición, su código termina atascado en un bucle infinito procesando el mismo búfer.

    Para corregirlo, agregue algo como:

     if data == b'': break 

    … después de la línea data = await loop.sock_recv(...) .

    Pero lo anterior aún no explica por qué wait_for no puede cancelar la coroutine deshonesta. El problema es que await no significa “pasar el control al bucle de eventos”, como se muestra a veces. Significa “solicitar valor del objeto esperado proporcionado, lo que otorga control al bucle de eventos si el objeto indica que no tiene un valor listo”. El si es crucial: si el objeto tiene un valor listo, este valor se usará inmediatamente sin tener que aplazar el ciclo de eventos. En otras palabras, await no garantiza que el bucle de eventos tenga la oportunidad de ejecutarse.

    Por ejemplo, la siguiente coroutine bloquea completamente el bucle de eventos e impide que alguna otra coroutine se ejecute, a pesar de que su bucle interno consiste en nada más que esperar:

     async def busy_loop(): while True: await noop() async def noop(): pass 

    En su ejemplo, dado que el socket no se bloquea en absoluto cuando se encuentra al final del archivo, la coroutine nunca se suspende, y (en colusión con el error anterior) su coroutine nunca sale.

    Para garantizar que otras tareas tengan la oportunidad de ejecutarse, puede agregar await asyncio.sleep(0) en un bucle. Esto no debería ser necesario para la mayoría de los códigos, donde la solicitud de datos de E / S pronto dará como resultado una espera, momento en el que se activará el bucle de eventos. El código se atasca solo en combinación con el error de manejo de EOF.