4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Dart で Thread ライクな処理 for Native & Webdev (1)

Last updated at Posted at 2020-08-03

ここでは、Dart の 非同期処理について解説します。
また、Native や Flutter だけでなく、Webdevについても解説します。

Dart の 非同期処理

dart:isolate を利用する事で、Threadライクな非同期処理を実現できます。
ただ、この dart:isolate には制限がって、Webでは動作しません
※ Dart1 系の頃は 動作していました。

ここでは、Dart1系のIsolateに習い、Worker を 利用してThreadライクな非同期処理を実現してみます。

Dart: isolate

Dartは非同期処理にはFutureを使うと思います。ただ、同時に処理を並行して動作させる事がFutureでは出来ません。

Background で動画のエンコードなどの重い処理を行いながら、Forgroundでは描画のアニメーションを行う。
といった事を行いたい場合、Isolateを利用します。

Isolateは、メモリの共有は出来ませんが、Threadのように動作します。
コードを見るのが早いと思います。

isolate_example_01.dart

import 'dart:isolate' as iso;

Future main() async {
  iso.ReceivePort receivePort = iso.ReceivePort();
  iso.Isolate.spawn(workerMain, receivePort.sendPort);

  receivePort.listen((message) {
    print("host: ${message}");
  });
}

workerMain(sendPort) async { 
    for(var message in ["01","02","03"]) {
        (sendPort as iso.SendPort).send(message);
        await Future.delayed(Duration(seconds: 1));
    }
}

workerMain() を、Isolate 上で起動して、その結果を、
受け取るコードです。

Worker

Dart2系では、Webdevでdart:isolate が利用出来ません。
Dart1系のdart:isolate にならい、Worker を利用してみましょう。

parent.dart
import 'dart:html' as html;

main() async {
  if(html.Worker.supported) {
      var myWorker = new html.Worker("ww.dart.js");
      myWorker.onMessage.listen((event) {
        print("main:receive: ${event.data}");
      });
      myWorker.postMessage("Hello!!");
  } else {
    print('Your browser doesn\'t support web workers.');
  }
}


child.dart

import 'dart:async';
import 'dart:html' as html;

import 'dart:js' as js;
import 'package:js/js.dart' as pjs;
import 'package:js/js_util.dart' as js_util;

@pjs.JS('self')
external dynamic get globalScopeSelf;


Stream<T> callbackToStream<J, T>(String name, T Function(J jsValue) unwrapValue) {
  var controller = StreamController<T>.broadcast(sync: true);
  js_util.setProperty(js.context['self'], name, js.allowInterop((J event) {
    controller.add(unwrapValue(event));
  }));
  return controller.stream;
}

void jsSendMessage( dynamic object, dynamic m) {
  js.context.callMethod('postMessage',[m]);
}

main() {
    callbackToStream('onmessage', (html.MessageEvent e)  {
      return js_util.getProperty(e, 'data');
    }).listen((message) {
      print('>>> ${message}');
      jsSendMessage(js.context, 'callback: ${message}');
    });
}

PS

Dart:Isolate 親から子へメッセージを送信したい場合

iso.SendPort を  メッセージで渡す事ができます。
ので、子側で、(new iso.ReceivePort()).sendPort を、親にメッセージで渡してください!!

parent.dart
import 'dart:isolate' as iso;
Future<int> main(List<String> args, iso.SendPort sendPoet) async {
  print("Start Main");
  iso.ReceivePort receivePort = iso.ReceivePort();
  receivePort.listen((message) {
    print("main:receive: ${message}");
    if(message is iso.SendPort) {
      (message as iso.SendPort).send("Hello!! Client");
    }
  });
  
  await iso.Isolate.spawnUri(new Uri.file("./child.dart"), [], receivePort.sendPort);

  return 0;
}

child.dart
import 'dart:isolate' as iso;

int main(List<String> args, iso.SendPort sendPort) {
  print("Hello, World!!");
  sendPort.send("Start a child");
  iso.ReceivePort receivePort = iso.ReceivePort();
  receivePort.listen((message) {
    print("child: receive message: ${message}");
    sendPort.send(message);
  });
  sendPort.send(receivePort.sendPort);

  return 0;
}


dart2native の制限

iso.Isolate.spawnUri  を使う場合、dart2native を利用すると、

Unsupported operation: Isolate.spawnUri is not supported when using AOT compilation

とエラー表示されますので、dart2nativeを利用したい場合は、Isolate.spawnを使用するようにしましょう!!

webdev の制限

webdev serve だと Worker が上手く動作しませんでした
dart2js web/xxx.dart -o web/xxx.dart.js として、Workerは手動でビルドしてください

code

今回のコードは以下の通り
https://github.com/kyorohiro/dart.tiny_worker

次回

共通のInterface で動作するようにしてみます。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?