4

スレッド/非同期の方法については、Javaに関連しています。Java でスレッド化を行う 1 つの方法として、ターゲットが Runnable である new Thread(target).start() を使用します。新しい並行 API には代替手段がありますが、特定の呼び出しで新しいスレッドが作成され、タスクに渡されて実行されることがわかっています。

同様に、Dart で async はどのように行われますか? send/receivport、completer/future、spawnFunction を読みました。私にとって spawnFunction だけが、新しいスレッドを作成する説得力のあるステートメントです。どのように完全な/将来の助けになるかを説明できますか. 私は彼らがコールバックを取ることを知っていますが、javascript/dart には、コールバックが常に別のスレッドで実行されるという暗黙のロジック/ルールがあります。

以下は dart スニペット/疑似コードです。

void callback() {
  print("callback called");
}

costlyQuery(sql, void f()) {
  executeSql(sql);
  f();
}

costlyQuery("select * from dual", callback);

第 2 パラメーターが正しいため、costlyQuery 署名が機能することを願っています。f()だから今、アフターexecuteSql(sql)が非同期になるとは思わない。上記の例を使用して、理解を助けるために非同期にすることができる場合は、コンプリータ/フューチャーを追加してください。

4

1 に答える 1

9

tl;dr : コールバックがブロックしないという暗黙のルールはありません。

JavaScript イベント キュー

Javascript には、スレッドはありません (WebWorkers を除きますが、それは異なります)。これは、コードの一部がブロックされると、アプリケーション全体がブロックされることを意味します。コールバックに魔法はありません。コールバックはただの関数です:

function longLoop(cb) {
    var i = 1000000;
    while (i--) ;
    cb();
}

function callback() {
    console.log("Hello world");
}

function fun() {
    longLoop(callback);
    console.log("Called after Hello World is printed");
}

何かを非同期にするには、コールバックをイベント キューに入れる必要があります。これは、一部の API 呼び出しでのみ発生します。

  • ユーザーが開始したイベント ハンドラー - クリック、キーボード、マウス
  • API イベント ハンドラー - XmlHTTPRequest コールバック、WebWorker 通信
  • タイミング関数 - setTimeout、setInterval

イベントがトリガーされると、コールバックはイベント キューに配置され、他のすべてのコールバックの実行が終了したときに実行されます。これは、コードの 2 行が同時に実行されることはないことを意味します。

先物

先物に関するこの投稿に少なくとも出くわしたと思います。そうでない場合、それは良い読み物であり、馬の口から直接出てきます.

Javascript では、非同期コードを理解するためにいくつかの作業を行う必要があります。非同期ループやシーケンスなどの一般的なことを行うための、futuresと呼ばれる Javascript ライブラリさえあります (完全な開示、私はこのライブラリの作成者と個人的に協力しました)。

未来の概念は、将来のある時点で未来が完成するという、未来を作成する機能によってなされる約束です。非同期呼び出しを行う場合は、future を作成し、それを返し、非同期呼び出しが終了したときに約束を果たします。ブログ投稿から:

Future<Results> costlyQuery() {
    var completer = new Completer();

    database.query("SELECT * FROM giant_table", (results) {
        // when complete
        completer.complete(results);
    });

    // this returns essentially immediately,
    // before query is finished
    return completer.future; 
}

database.query がブロッキング コールの場合、future はすぐに完了します。database.queryこの例では、非ブロッキング呼び出し (非同期) を想定しているため、この関数が終了した後にフューチャーが満たされます。指定された引数completer.completeで渡された関数を呼び出します。completer.then()

あなたの例は、慣用的で非同期になるように変更されています:

void callback() {
  print("callback called");
}

costlyQuery(sql) {
  var completer = new Completer();
  executeSql(sql, () => completer.complete());
  return completer.future;
}

costlyQuery("select * from dual").then(callback);

これは非同期で、先物を正しく使用します。独自のコールバック関数を に渡し、コールcostlyQueryバックでそれを呼び出してexecuteSql同じことを達成することもできますが、それは Dart の方法ではなく、Javascript の方法です。

分離する

アイソレートは Java のスレッドに似ていますが、アイソレートは同時実行モデルであり、スレッドは並列モデルです (同時実行と並列処理の詳細については、この SO の質問を参照してください)。

Dart は、仕様がすべてを単一のスレッドで実行することを義務付けていないという点で特別です。異なる実行コンテキストが同じデータにアクセスできないようにするだけです。各アイソレートには独自のメモリがあり、送受信ポートを介して他のアイソレートとのみ通信 (データの送信など) できます。

これらのポートは、よく知られている場合、Go のチャネルと同様に機能します。

分離は、他のコードから独立して実行される分離された実行コンテキストです。Javascript の用語では、これは独自のイベント キューがあることを意味します。分離株のより完全な紹介については、Dart ツアーを参照してください。

executeSql がブロッキング関数であるとしましょう。終了するのを待ちたくない場合は、isolate にロードできます。

void callback() {
    print("callback called");
}

void costlyQuery() {
    port.receive((sql, reply) {
        executeSql(sql);
        reply.send();
    });
}

main() {
    var sendPort = spawnFunction(costlyQuery);

    // .call does all the magic needed to communicate both directions
    sendPort.call("select * from dual").then(callback);

    print("Called before executeSql finishes");
}

このコードは、isolate を作成し、そこにデータを送信してから、完了時のコールバックを登録します。executeSqlブロックしても、main()必ずブロックするとは限りません。

于 2012-11-22T09:42:46.520 に答える