Python 3.5以降、キーワードawait
およびasync
が言語に導入されました。今、私はPython 2.7の人であり、かなり長い間Python 3を避けてきたので、asyncio
は私にとってかなり新しいものです。私の理解では、await/async
は、ES6(またはJavaScript、ES2015、ただし呼び出したい)での動作と非常によく似ているようです。
これらを比較するために作成した2つのスクリプトを次に示します。
import asyncio
async def countdown(n):
while n > 0:
print(n)
n -= 1
await asyncio.sleep(1)
async def main():
"""Main, executed in an event loop"""
# Creates two countdowns
futures = asyncio.gather(
countdown(3),
countdown(2)
)
# Wait for all of them to finish
await futures
# Exit the app
loop.stop()
loop = asyncio.get_event_loop()
asyncio.ensure_future(main())
loop.run_forever()
function sleep(n){
// ES6 does not provide native sleep method with promise support
return new Promise(res => setTimeout(res, n * 1000));
}
async function countdown(n){
while(n > 0){
console.log(n);
n -= 1;
await sleep(1);
}
}
async function main(){
// Creates two promises
var promises = Promise.all([
countdown(3),
countdown(2)
]);
// Wait for all of them to finish
await promises;
// Cannot stop interpreter's event loop
}
main();
注目すべき点の1つは、コードが非常によく似ており、ほとんど同じように機能することです。
ここに質問があります:
PythonとES6の両方で、await/async
はジェネレーターに基づいています。先物はプロミスと同じだと考えるのは正しいですか?
Task
のドキュメントで使用されているFuture
、Coroutine
、asyncio
という用語を見てきました。それらの違いは何ですか?
常にイベントループが実行されるPythonコードの記述を開始する必要がありますか?
- PythonとES6の両方で、_
await/async
_はジェネレータに基づいています。FutureはPromiseと同じであると考えるのは正しいですか?
Future
ではありませんが、PythonのTask
はJavascriptのPromise
とほぼ同等です。詳細は以下をご覧ください。
Task
ドキュメントで使用されているFuture
、Coroutine
、asyncio
という用語を見てきました。それらの違いは何ですか?
それらはまったく異なる概念です。主に、Task
はFuture
とCoroutine
で構成されます。これらのプリミティブについて簡単に説明しましょう(主な原則のみを説明するために、多くのことを簡略化します)。
将来
Futureは、まだ計算されていない可能性があり、最終的には使用可能になる値の抽象化です。これは、1つのことだけを行う単純なコンテナです。値が設定されるたびに、登録されているすべてのコールバックを起動します。
その値を取得したい場合は、add_done_callback()
メソッドを介してコールバックを登録します。
ただし、Promise
とは異なり、実際の計算は外部で行われます。その外部コードは、将来を解決するためにset_result()
メソッドを呼び出す必要があります。
コルーチン
コルーチンはGenerator
によく似たオブジェクトです。
ジェネレータは通常、for
ループ内で反復されます。それはyields値であり、 PEP342 受け入れから始まり、それはreceives値です。
コルーチンは通常、asyncio
ライブラリの深さでイベントループ内で反復されます。コルーチンはFuture
インスタンスを生成します。コルーチンを反復処理してフューチャーを生成する場合、このフューチャーが解決されるまで待機する必要があります。その後、コルーチンへのfutureの値をsend
し、別のfutureを受け取ります。
await
式は、実質的に_yield from
_式と同一であるため、他のコルーチンを待つことにより、そのコルーチンがすべての先物を解決するまで停止し、コルーチンの戻り値。 Future
は1ティックの反復可能であり、そのイテレータは実際のFutureを返します。つまり、_await future
_は_yield from future
_は_yield future
_と等しいことを大まかに意味します。
タスク
タスクは、実際に計算を開始し、イベントループに接続されているFutureです。したがって、これは特別な種類のFuture(クラスTask
はクラスFuture
から派生)であり、いくつかのイベントループに関連付けられており、として機能するいくつかのコルーチンを持っていますタスク実行者。
タスクは通常、イベントループオブジェクトによって作成されます。ループにコルーチンを指定すると、タスクオブジェクトが作成され、上記の方法でそのコルーチンの反復処理が開始されます。コルーチンが完了すると、タスクのFutureはコルーチンの戻り値によって解決されます。
ご覧のとおり、このタスクはJS Promiseに非常に似ています-バックグラウンドジョブとその結果をカプセル化します。
コルーチン関数と非同期関数
コルーチンfuncは、ジェネレーターに対するジェネレーター関数のようなコルーチンのファクトリーです。 Pythonのコルーチン関数とJavaScriptの非同期関数の違いに注意してください。JS非同期関数が呼び出されると、Promiseが作成され、その内部ジェネレーターがすぐに反復されますが、Pythonのコルーチンは、タスクが作成されるまで何もしません。
- Python常にイベントループが実行されるコードを記述し始める必要がありますか?
Asyncio機能が必要な場合は、必要です。結局のところ、同期コードと非同期コードを混在させることは非常に困難です。プログラム全体を非同期にした方がよいでしょう(ただし、asyncioスレッドプールAPIを使用して、同期コードチャンクを別々のスレッドで起動できます)
PtyhonとES6のawait/asyncはほとんど同じですが、いくつかの詳細は除きます。
Promise
Pythonに基づいています:await/asyncはFutures
に基づいています。ジェネレータはこれとは何の関係もありません。