blog

[Dartの非同期におけるアイソレートとイベントループ

Dartはシングルスレッド言語であり、future、stream、wotk、その他のイベントを非同期で提供します。Flutterのために、この章ではDartのバックエンド作業の基本であるアイソレータと...

Apr 21, 2020 · 4 min. read
シェア

Dartはシングルスレッド言語であり、future、stream、background wotk、その他のイベント、非同期、そしてFlutterのために、この章ではDartのバックエンド作業の基本である分離とイベントループについて説明します。

Isolates

Dartのコードはすべて、その中で孤立したプログラムを実行します。これはマシン上の小さな空間のようなもので、専用のメモリ・ブロックと、イベント・ループを実行する単一のスレッドがあります。

他の多くの言語では、複数のスレッドが同じメモリを共有し、必要なコードを実行することができます。しかし Dart では、各スレッドはそれぞれ独立し、独自のメモリを持ち、そのスレッドはイベントのみを処理します。

多くのDartアプリケーションは全てのコードを1つのisolationで実行しますが、必要に応じて複数のisolationを持つことができます。実行される計算の量が非常に大きく、メインのアイソレータで実行するとフレームが落ちる可能性がある場合は、Isolate.spawn 関数を使用することができます。どちらの関数も数値を処理するために別のアイソレータを作成し、メインのアイソレータはウィジェットツリーの再構築とレンダリングに自由に使えるようになります。

新しいアイソレーションには独自のイベントループとメモリがあり、元のアイソレーションはその新しいアイソレーションの親であるにもかかわらずアクセスすることができません。これがアイソレーションというものです。

実際、アイソレータが連携する唯一の方法はメッセージの受け渡しです。一方のアイソレータがもう一方のアイソレータにメッセージを送信し、受信側のアイソレータがイベントループを使ってメッセージを処理します。

共有メモリがないことは、特にJavaやC ++のような言語を使用している場合、厳しく聞こえるかもしれませんが、Dartコーダーにとって重要な利点があります。

例えば、分離された状態でのメモリ割り当てやゴミの収集にはロックは必要ありません。スレッドは1つだけなので、忙しくなければメモリが変更されていないことがわかります。これは、ウィジェットの束を素早くビルドしたり取り出したりする必要のあるFlutterアプリに効果的です。

Event loops

さて、分離の基本を学んだところで、非同期コードを本当に可能にするもの、イベントループに飛び込んでみましょう。アプリケーションのライフサイクルがタイムライン上に延びることを想像してみてください。アプリケーションが起動し、アプリケーションが停止し、その間に一連のイベントが発生します。アプリケーションは、これらのイベントがいつ、どのような順序で発生するかを予測することができないため、これらのイベントをすべて処理するために、決してブロックしないスレッドを使用する必要があります。そのため、アプリケーションはイベントループを実行します。イベント・キューから最も古いイベントを取り出し、それを処理し、次のイ ベントに戻り、それを処理し......と、イベント・キューが空になるまで繰り返します。アプリケーションの実行時間中、画面をタップし、コンテンツをダウンロードし、タイマーが切れるまで、このイベントループはループし続け、これらのイベントを1つずつ処理します。

操作が中断されると、スレッドはただぶらぶらして次のイベントを待ちます。ゴミコレクタを起動したり、コーヒーを飲んだり、といった具合です。非同期プログラミングのためのDartの高レベルAPIと言語機能はすべて、この単純なループに基づいて構築されています。例えば、以下のようにWebリクエストを開始するボタンがあるとします:

RaisedButton(
 child: Text('Click me'),
 onPressed: () {
 final myFuture = http.et('ps://.om');
 myFuture.then((response) {
 if (response.statusCode == 200) {
 print('Success!');
 }
 });
 },
)

アプリを起動すると、Flutterはこのボタンをコンパイルしてレンダリングし、アプリはイベントを待ち始めます。

アプリケーションのイベントループは、次のイベントを待ちながら、ただアイドル状態になっています。ボタンに関係のないイベントが入り、ボタンがユーザがクリックするのを待っている間に処理されるかもしれません。やがてユーザーがクリックすると、クリックイベントはキューに入ります。

イベントが処理されます。 Flutterはそれを見て、レンダリングシステムが「その座標は上げられたボタンと一致する」と言うので、FlutterはonPressed関数を実行します。コードはウェブリクエストを開始し、then()メソッドを使って未来の完了ハンドラを登録します。そしてもう。ループはそのクリックイベントを終了し、破棄しています。さて、onPressed は RaisedButton のプロパティであり、ネットワークイベントは将来の使用のためにコールバックされますが、どちらのテクニックも基本的な操作は同じです。どちらもFlutterに「ねぇ、後で特定のタイプのイベントを見るかもしれないよ。そのときはこのコードを実行してください "とFlutterに伝える方法です。onPressedはクリック待ちで、Futureはネットワークデータ待ちですが、Dartから見ればこれらはキュー内のイベントに過ぎません。これがDartにおける非同期コーディングの仕組みです。Future、データストリーム、非同期、待機、これらのAPIは、Dartのイベントループに「ここにコードがあります。コード例を見直すと、特定のイベントの塊にどのように分解されているかがよくわかります。 初期バージョン、クリック・イベント、ネットワーク・レスポンス・イベントです。

RaisedButton( // (1)
 child: Text('Click me'),
 onPressed: () { // (2)
 final myFuture = http.et('ps://.om');
 myFuture.then((response) { // (3)
 if (response.statusCode == 200) {
 print('Success!');
 }
 });
 },
)

非同期コードに慣れてくると、このようなパターンがあちこちで見られるようになります。イベントループを理解することは、より高度なAPIを使い続ける際に役立ちます。

Dartにおける分離、イベントループ、非同期コーディングの基本について簡単に説明します。マイクロタスクキューがどのように機能するかなど、より詳細な情報をお探しの場合は、古いが今でも愛されているイベントループとDartの記事を参照してください。

Read next

JVMを知る

クラスが仮想マシンのメモリにロードされてからメモリからアンロードされるまでのライフサイクル全体は、ロード、検証、準備、解析、初期化、使用、アンロードの7つのフェーズで構成されます。クラス・ロードのプロセスは、ロード、検証、準備、構文解析、および初期化の 5 つのフェーズで構成されます。 これらのデータのメソッド領域として、このクラスを表すClassオブジェクトをヒープに生成します。

Apr 21, 2020 · 15 min read

異形のES6エッセイ

Apr 21, 2020 · 6 min read

天地乾坤借用法

Apr 20, 2020 · 9 min read

CSS基礎の復習 - 相対単位

Apr 20, 2020 · 2 min read