python asynchronous async-await python-3.4 python-3.5

`async for` en Python 3.4



asynchronous async-await (1)

¿Hay una forma de transformar un Python 3.5 async for declaración en un código Python 3.4?

PEP 0492 dice que async for

async for TARGET in ITER: BLOCK else: BLOCK2

es equivalente a

iter = (ITER) iter = type(iter).__aiter__(iter) running = True while running: try: TARGET = await type(iter).__anext__(iter) except StopAsyncIteration: running = False else: BLOCK else: BLOCK2

pero __aiter__ no existe en Python 3.4


No, no hay, async/await __aiter__ ( __aiter__ , etc también) se introdujo en Python 3.5. En py3.4, lo más cercano es asyncio.gather (si puede ejecutar todas las tareas a la vez / en paralelo y esperar hasta que finalicen) o asyncio.Queue resultados en un asyncio.Queue (que es secuencial, igual que async for ). Editar: vea el último ejemplo de un async for alternativa, como se describe en la pregunta.

Aquí hay un ejemplo de ala python docs para asyncio.gather:

import asyncio @asyncio.coroutine def task(id): print("task: {}".format(id)) yield from asyncio.sleep(random.uniform(1, 3)) return id tasks = [ task("A"), task("B"), task("C") ] loop = asyncio.get_event_loop() results = loop.run_until_complete(asyncio.gather(*tasks)) loop.close() print(results)

Salida:

task: B task: A task: C [''A'', ''B'', ''C'']

Aquí hay uno para asyncio.Queue:

import asyncio @asyncio.coroutine def produce(queue, n): for x in range(n): print(''producing {}/{}''.format(x, n)) # todo: do something more useful than sleeping :) yield from asyncio.sleep(random.random()) yield from queue.put(str(x)) @asyncio.coroutine def consume(queue): while True: item = yield from queue.get() print(''consuming {}...''.format(item)) # todo: do something more useful than sleeping :) yield from asyncio.sleep(random.random()) queue.task_done() @asyncio.coroutine def run(n): queue = asyncio.Queue() # schedule the consumer consumer = asyncio.ensure_future(consume(queue)) # run the producer and wait for completion yield from produce(queue, n) # wait until the consumer has processed all items yield from queue.join() # the consumer is still awaiting for an item, cancel it consumer.cancel() loop = asyncio.get_event_loop() loop.run_until_complete(run(10)) loop.close()

Edit: async for alternativa como se describe en la pregunta:

import asyncio import random class StopAsyncIteration(Exception): """""" class MyCounter: def __init__(self, count): self.count = count def __aiter__(self): return self @asyncio.coroutine def __anext__(self): if not self.count: raise StopAsyncIteration return (yield from self.do_something()) @asyncio.coroutine def do_something(self): yield from asyncio.sleep(random.uniform(0, 1)) self.count -= 1 return self.count @asyncio.coroutine def getNumbers(): i = MyCounter(10).__aiter__() while True: try: row = yield from i.__anext__() except StopAsyncIteration: break else: print(row) loop = asyncio.get_event_loop() loop.run_until_complete(getNumbers()) loop.close()

Tenga en cuenta que esto se puede simplificar eliminando tanto __aiter__ como __anext__ y elevando una excepción de detención dentro del do_something método do_something o devolviendo un resultado de centinela cuando haya terminado (generalmente un valor no válido como: None , "" , -1 , etc.)