web-dev-qa-db-ja.com

Pythonでループを非同期にする

次のコードは次のように出力します。

1 sec delay, print "1", 
1 sec delay, print "2", 
1 sec delay, print "1", 
1 sec delay, print "2"

次のように実行するように変更するにはどうすればよいですか。

1 sec delay, print "1", print "1",
1 sec delay, print "2", print "2"

Forループの両方のインスタンスが同時に実行を開始するように実行します。各インスタンスが実行されると、first()関数が同時に検出され、次にsecond()関数が同時に検出されるため、上記の順序で出力されます。

コード:

import asyncio

async def first():
    await asyncio.sleep(1)
    return "1"

async def second():
    await asyncio.sleep(1)
    return "2"

async def main():     
    for i in range(2):
      result = await first()
      print(result)
      result2 = await second()
      print(result2)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
3
Canis Lobo

目的の出力を見ると、目標は個々の反復をそのままにすることです。つまり、firstsecondを順次実行しますが、両方のループ反復を並列に実行します。

main()のみを変更したい場合、次のように実行できます。

async def main():
    async def one_iteration():
        result = await first()
        print(result)
        result2 = await second()
        print(result2)
    coros = [one_iteration() for _ in range(2)]
    await asyncio.gather(*coros)

上記は、順番に繰り返す代わりに、反復タスクごとにコルーチンを作成し、 asyncio.gather すべての反復を並行して実行します。

コルーチンを作成しただけでは実行が開始されないため、多数のcorosによってイベントループがブロックされることはありません。

9
user4815162342

Aysncioライブラリを使用すると、aysncio.gather()を使用できます

loop.run_until_complete(asyncio.gather(
  first(),
  second()
))

これは、HTTPリクエストも並行して送信する場合に便利です。

loop.run_until_complete(asyncio.gather(
  request1(),
  request2()
))
2
Wajih Qazi

2つの関数を同時に実行するには、 gather を使用できます。ただし、結果は提供された順序で提供されます。だから例えばあなたがするなら

_results = await asyncio.gather(first(), second())
_

次に、[the result of first(), the result of second()]が返されます。それぞれが戻るたびに何かを実行したい場合は、Tasksを明示的に使用し、 コールバックを追加 を使用する必要があります。

1
Nick Chapman