私は、さまざまな方法で同じ操作を実行する asyncio に関する基本的な Python 3.5 チュートリアルをいくつか見てきました。このコードでは:
import asyncio
async def doit(i):
print("Start %d" % i)
await asyncio.sleep(3)
print("End %d" % i)
return i
if __name__ == '__main__':
loop = asyncio.get_event_loop()
#futures = [asyncio.ensure_future(doit(i), loop=loop) for i in range(10)]
#futures = [loop.create_task(doit(i)) for i in range(10)]
futures = [doit(i) for i in range(10)]
result = loop.run_until_complete(asyncio.gather(*futures))
print(result)
変数を定義する上記の 3 つのバリアントはすべてfutures
同じ結果を達成します。私が確認した唯一の違いは、3 番目のバリアントでは実行が順序どおりに行われないことです (ほとんどの場合、これは問題になりません)。他に違いはありますか? 最も単純なバリアント (コルーチンの単純なリスト) を使用できないケースはありますか?
ベストアンサー1
実際の情報:
asyncio.create_task(coro)
Python 3.7の高レベル関数から始める追加されたこの目的のために。
coroutimes からタスクを作成する他の方法の代わりに、これを使用する必要があります。ただし、任意の awaitable からタスクを作成する必要がある場合は、を使用する必要がありますasyncio.ensure_future(obj)
。
古い情報:
ensure_future
対create_task
ensure_future
作成する方法ですTask
からcoroutine
引数に基づいてさまざまな方法でタスクを作成します (コルーチンや future のようなオブジェクトに を使用するなどcreate_task
)。
create_task
は の抽象メソッドですAbstractEventLoop
。イベント ループによってこの関数の実装方法は異なります。
タスクを作成するには を使用する必要があります。独自のイベント ループ タイプを実装する場合にのみensure_future
必要になります。create_task
更新:
@bj0が指摘したグイドの答えこのトピックにおいて:
のポイント
ensure_future()
は、コルーチンまたは(のサブクラスであるためFuture
、後者には が含まれます)のいずれかになるものがあり、 でのみ定義されているメソッド(おそらく が唯一の有用な例です)を呼び出せるようにしたい場合です。 がすでに(または)である場合、これは何もしません。コルーチンである場合は、Task
Future
Future
cancel()
Future
Task
ラップそれをTask
。コルーチンがあることがわかっていて、それをスケジュールしたい場合は、使用する正しい API は です
create_task()
。 を呼び出す必要があるのは、ensure_future()
コルーチンまたは のいずれかを受け入れる API (ほとんどの asyncio 独自の API など) を提供しFuture
、 を必要とする操作をその API に対して実行する必要がある場合のみですFuture
。
以降:
結局のところ、
ensure_future()
めったに必要とされない機能に対しては、 は適切なわかりにくい名前だと思っています。コルーチンからタスクを作成するときは、適切な名前の を使用する必要がありますloop.create_task()
。おそらく、それには別名が必要でしょうかasyncio.create_task()
?
私にとっては驚きです。私がensure_future
ずっとこれを使う主な動機は、ループのメンバーと比較して、これがより高レベルの関数であるということでしたcreate_task
(議論含むasyncio.spawn
または を追加するなどのアイデアもありますasyncio.create_task
。
Awaitable
また、私の意見では、コルーチンのみではなく、あらゆるものを処理できるユニバーサル関数を使用するのが非常に便利だとも言えます。
しかし、グイドの答えは明確です。「コルーチンからタスクを作成するときは、適切な名前のloop.create_task()
「
コルーチンをタスクにラップする必要があるのはいつですか?
コルーチンをタスクにラップする - これは、このコルーチンを「バックグラウンド」で開始する方法です。次に例を示します。
import asyncio
async def msg(text):
await asyncio.sleep(0.1)
print(text)
async def long_operation():
print('long_operation started')
await asyncio.sleep(3)
print('long_operation finished')
async def main():
await msg('first')
# Now you want to start long_operation, but you don't want to wait it finised:
# long_operation should be started, but second msg should be printed immediately.
# Create task to do so:
task = asyncio.ensure_future(long_operation())
await msg('second')
# Now, when you want, you can await task finised:
await task
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
出力:
first
long_operation started
second
long_operation finished
違いを実感するためにasyncio.ensure_future(long_operation())
、 と交換することもできます。await long_operation()