Aby utrzymać wzrost stosu, należy zezwolić na to, aby każdy z nich rzeczywiście zakończył działanie po zaplanowaniu następnego wywołania rekursywnego, co oznacza, że należy unikać używania yield from
. Zamiast tego, używasz asyncio.async
(lub asyncio.ensure_future
, jeśli używasz Python 3.4.4+), aby zaplanować następną coroutine z pętlą zdarzeń, i użyć Future.add_done_callback
, aby zaplanować wywołanie zwrotne do uruchomienia po wywołaniu rekursywnego. Każdy coroutine następnie zwraca obiekt asyncio.Future
, który ma swój zestaw wyników wewnątrz wywołania zwrotnego, które jest uruchamiane, gdy zaplanowane wywołanie rekurencyjne zostanie ukończone.
To chyba najłatwiejszy do zrozumienia, jeśli rzeczywiście zobaczyć kod:
import asyncio
@asyncio.coroutine
def a(n):
fut = asyncio.Future() # We're going to return this right away to our caller
def set_result(out): # This gets called when the next recursive call completes
fut.set_result(out.result()) # Pull the result from the inner call and return it up the stack.
print("A: {}".format(n))
if n > 1000:
return n
else:
in_fut = asyncio.async(b(n+1)) # This returns an asyncio.Task
in_fut.add_done_callback(set_result) # schedule set_result when the Task is done.
return fut
@asyncio.coroutine
def b(n):
fut = asyncio.Future()
def set_result(out):
fut.set_result(out.result())
print("B: {}".format(n))
in_fut = asyncio.async(a(n+1))
in_fut.add_done_callback(set_result)
return fut
loop = asyncio.get_event_loop()
print("Out is {}".format(loop.run_until_complete(a(0))))
Output:
A: 0
B: 1
A: 2
B: 3
A: 4
B: 5
...
A: 994
B: 995
A: 996
B: 997
A: 998
B: 999
A: 1000
B: 1001
A: 1002
Out is 1002
Teraz Twój przykładowy kod faktycznie nie wrócić n
całą drogę z powrotem na stos, więc można zrobić coś funkcjonalnie równoważne to nieco prostsze:
import asyncio
@asyncio.coroutine
def a(n):
print("A: {}".format(n))
if n > 1000: loop.stop(); return n
else: asyncio.async(b(n+1))
@asyncio.coroutine
def b(n):
print("B: {}".format(n))
asyncio.async(a(n+1))
loop = asyncio.get_event_loop()
asyncio.async(a(0))
loop.run_forever()
Ale podejrzewam, że naprawdę oznaczało powrót n
całą drogę z powrotem do góry.
za każdym razem, gdy "ustąpisz", podpinacie się do następnego połączenia. Czy próbowałeś użyć kolejki? W ten sposób możesz przekazać informacje i zapisać je w kolejnym korupcji bez łączenia ich ze sobą. – shongololo