実行中のasyncioループに新しいコルーチンを追加するにはどうすればよいですか?すなわち。すでにコルーチンのセットを実行しているもの。
回避策として、既存のコルーチンが完了するのを待ってから、新しいループを(追加のコルーチンを使用して)初期化できると思います。しかし、もっと良い方法はありますか?
create_task
新しいコルーチンをスケジュールする場合:
import asyncio
async def cor1():
...
async def cor2():
...
async def main(loop):
await asyncio.sleep(0)
t1 = loop.create_task(cor1())
await cor2()
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
既に実行中のイベントループに関数を追加するには、次を使用できます。
asyncio.ensure_future(my_coro())
私の場合、マルチスレッド(threading
)をasyncio
とともに使用しており、既に実行中のイベントループにタスクを追加したいと考えていました。同じ状況にいる他の人には、イベントループを明示的に記述してください(Thread
内には存在しないため)。すなわち:
グローバルスコープ:
event_loop = asyncio.get_event_loop()
その後、Thread
内で:
asyncio.ensure_future(my_coro(), loop=event_loop)
あなたの質問は「実行中のプログラムに関数呼び出しを追加する方法」に非常に近いです。
イベントループに新しいコルーチンを追加する必要があるのはいつですか?
いくつかの例を見てみましょう。ここで、2つのコルーチンを並行して使用してイベントループを開始するプログラム:
import asyncio
from random import randint
async def coro1():
res = randint(0,3)
await asyncio.sleep(res)
print('coro1 finished with output {}'.format(res))
return res
async def main():
await asyncio.gather(
coro1(),
coro1()
) # here we have two coroutines running parallely
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
出力:
coro1 finished with output 1
coro1 finished with output 2
[Finished in 2.2s]
coro1
の結果を取得し、準備ができたらすぐに使用するコルーチンを追加する必要があるかもしれません。その場合は、coro1
を待つコルーチンを作成し、それを使用して値を返します。
import asyncio
from random import randint
async def coro1():
res = randint(0,3)
await asyncio.sleep(res)
print('coro1 finished with output {}'.format(res))
return res
async def coro2():
res = await coro1()
res = res * res
await asyncio.sleep(res)
print('coro2 finished with output {}'.format(res))
return res
async def main():
await asyncio.gather(
coro2(),
coro2()
) # here we have two coroutines running parallely
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
出力:
coro1 finished with output 1
coro2 finished with output 1
coro1 finished with output 3
coro2 finished with output 9
[Finished in 12.2s]
コルーチンは、特定の構文を持つ通常の関数について考えてください。 (asyncio.gather
によって)いくつかの関数セットを並列に実行し、最初に実行した後に次の関数を開始できます。他の関数を呼び出す新しい関数を作成できます。
ここでの答えはどれも、質問に正確に答えているようには見えません。 「親」タスクに実行させることで、実行中のイベントループにタスクを追加することができます。親が子がすべて終了するまで終了しないことを確認するための最もPython的な方法はわかりません(それがあなたの望む動作だと仮定して)が、これは機能します。
import asyncio
import random
async def add_event(n):
print('starting ' + str(n))
await asyncio.sleep(n)
print('ending ' + str(n))
return n
async def main(loop):
added_tasks = []
delays = [x for x in range(5)]
# shuffle to simulate unknown run times
random.shuffle(delays)
for n in delays:
print('adding ' + str(n))
task = loop.create_task(add_event(n))
added_tasks.append(task)
await asyncio.sleep(0)
print('done adding tasks')
# make a list of tasks that (maybe) haven't completed
running_tasks = added_tasks[::]
# wait until we see that all tasks have completed
while running_tasks:
running_tasks = [x for x in running_tasks if not x.done()]
await asyncio.sleep(0)
print('done running tasks')
# extract the results from the tasks and return them
results = [x.result() for x in added_tasks]
return results
loop = asyncio.get_event_loop()
results = loop.run_until_complete(main(loop))
loop.close()
print(results)