web-dev-qa-db-ja.com

Python3のFutureとES6のPromiseの違い

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つは、コードが非常によく似ており、ほとんど同じように機能することです。

ここに質問があります:

  1. PythonとES6の両方で、await/asyncはジェネレーターに基づいています。先物はプロミスと同じだと考えるのは正しいですか?

  2. Taskのドキュメントで使用されているFutureCoroutineasyncioという用語を見てきました。それらの違いは何ですか?

  3. 常にイベントループが実行されるPythonコードの記述を開始する必要がありますか?

19
  1. PythonとES6の両方で、_await/async_はジェネレータに基づいています。FutureはPromiseと同じであると考えるのは正しいですか?

Futureではありませんが、PythonのTaskはJavascriptのPromiseとほぼ同等です。詳細は以下をご覧ください。

  1. Taskドキュメントで使用されているFutureCoroutineasyncioという用語を見てきました。それらの違いは何ですか?

それらはまったく異なる概念です。主に、TaskFutureCoroutineで構成されます。これらのプリミティブについて簡単に説明しましょう(主な原則のみを説明するために、多くのことを簡略化します)。

将来

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のコルーチンは、タスクが作成されるまで何もしません。

  1. Python常にイベントループが実行されるコードを記述し始める必要がありますか?

Asyncio機能が必要な場合は、必要です。結局のところ、同期コードと非同期コードを混在させることは非常に困難です。プログラム全体を非同期にした方がよいでしょう(ただし、asyncioスレッドプールAPIを使用して、同期コードチャンクを別々のスレッドで起動できます)

25
Andriy Maletsky

PtyhonとES6のawait/asyncはほとんど同じですが、いくつかの詳細は除きます。

  1. ES6、await/asyncはPromise Pythonに基づいています:await/asyncはFuturesに基づいています。ジェネレータはこれとは何の関係もありません。
  2. 続きを読む、あなたは理解するでしょう...コルーチンは並列プログラミング用であり、コルーチンの結果を未来として説明する方法があります
  3. 意味のあるイベントループを使用する(イベントドリブンサーバーまたはGUI)
0
Walle Cyril