异步Isolate实现多线程

 

最近在看Flutter开发相关知识点,对照着Android原生,探究了下多线程实现方式。在Flutter中有 Isolate,隔离,它的实现原理并不是内存共享的,它更像是一个进程。

最简单的 compute

import 'dart:convert';

main(List<String> args) {
String jsonString = '''{ "id":"1234", "name":"hahaha"}''';
People people = parseJson(jsonString);
print(people.name);
} Student parseJson(String json) {
Map<String, dynamic> map = jsonDecode(json);
return People.fromJson(map);
} class People{
String id;
String name;
People({this.id, this.name});
factory People.fromJson(Map parsedJson) {
return People(id: parsedJson['id'], name: parsedJson['name']);
}
} 我们需要把上面代码放入isolate中执行 isolate
Future<People> loadPeople(String json) {
return compute(parseJson, json);
} Student parseJson(String json) {
Map<String, dynamic> map = jsonDecode(json);
return People.fromJson(map);
}
compute是 Flutter 的 api ,帮我们封装了 isolate,使用十分简单,但是也有局限性, 它没有办法多次返回结果,也没有办法持续性的传值计算,
每次调用,相当于新建一个隔离,如果同时调用过多的话反而会多次开辟内存。在某些业务下,我们可以使用compute,
但是在另外一些业务下,我们只能使用dart提供的 isolate了。这个有点像AIDL和Messager的关系。
 
import 'dart:convert';
import 'dart:isolate'; main(List<String> args) async {
await start();
} Isolate isolate; start() async {
//创建接收端口,用来接收子线程消息
ReceivePort receivePort = ReceivePort(); //创建并发Isolate,并传入主线程发送端口
isolate = await Isolate.spawn(entryPoint, receivePort.sendPort);
//监听子线程消息
receivePort.listen((data) {
print('Data:$data');
});
} //并发Isolate
entryPoint(SendPort sendPort) {
String jsonString = '''{ "id":"123", "name":"张三"}''';
People people = parseJson(jsonString);
sendPort.send(people);
} Student parseJson(String json) {
Map<String, dynamic> map = jsonDecode(json);
return People.fromJson(map);
} class people {
String id;
String name;
People({this.id, this.name});
factory People.fromJson(Map parsedJson) {
return People(id: parsedJson['id'], name: parsedJson['name']);
}
}

我们需要从主线程传参给子线程,或者像线程池一样可以管理这个isolate,那么我们就需要实现双向通信:
import 'dart:isolate';

main(List<String> args) async {
// 在主线程里面
await start();
await Future.delayed(Duration(seconds: 1), () {
threadPort.send('主线程');
print('1');
});
await Future.delayed(Duration(seconds: 1), () {
threadPort.send('我也来自主线程');
print('2');
});
await Future.delayed(Duration(seconds: 1), () {
threadPort.send('end');
print('3');
});
} Isolate isolate;
//子线程发送端口
SendPort threadPort;
start() async {
// 在主线程
//创建主线程接收端口,用来接收子线程消息
ReceivePort receivePort = ReceivePort(); //创建并发Isolate,并传入主线程发送端口
isolate = await Isolate.spawn(entryPoint, receivePort.sendPort);
//监听子线程消息
receivePort.listen((data) {
print('主线程收到来自子线程的消息$data');
if (data is SendPort) {
threadPort = data;
}
});
} //并发Isolate
entryPoint(dynamic message) {
// 在子线程里面
//创建子线程接收端口,用来接收主线程消息
ReceivePort receivePort = ReceivePort(); SendPort sendPort;
print('==entryPoint==$message');
if (message is SendPort) {
sendPort = message;
print('子线程开启');
sendPort.send(receivePort.sendPort);
//监听子线程消息
receivePort.listen((data) {
print('子线程收到来自主线程的消息$data');
assert(data is String);
if (data == 'end') {
isolate?.kill();
isolate = null;
print('子线程结束');
return;
}
});
return;
}
}
双向通信比较复杂,所以我们需要封装下,通过 api 让外部调用:
import 'dart:async';
import 'dart:isolate'; main(List<String> args) async {
var worker = Worker();
worker.reuqest('发送消息1').then((data) {
print('子线程处理后的消息:$data');
}); Future.delayed(Duration(seconds: 2), () {
worker.reuqest('发送消息2').then((data) {
print('子线程处理后的消息:$data');
});
});
} class Worker {
SendPort _sendPort;
Isolate _isolate;
final _isolateReady = Completer<void>();
final Map<Capability, Completer> _completers = {}; Worker() {
init();
} void dispose() {
_isolate.kill();
} Future reuqest(dynamic message) async {
await _isolateReady.future;
final completer = new Completer();
final requestId = new Capability();
_completers[requestId] = completer;
_sendPort.send(new _Request(requestId, message));
return completer.future;
} Future<void> init() async {
  // 在主线程里面
final receivePort = ReceivePort();
final errorPort = ReceivePort();
errorPort.listen(print);
receivePort.listen(_handleMessage);
_isolate = await Isolate.spawn(
_isolateEntry,
receivePort.sendPort,
onError: errorPort.sendPort,
);
} void _handleMessage(message) {
if (message is SendPort) {
_sendPort = message;
_isolateReady.complete();
return;
}
if (message is _Response) {
final completer = _completers[message.requestId];
if (completer == null) {
print("Invalid request ID received.");
} else if (message.success) {
completer.complete(message.message);
} else {
completer.completeError(message.message);
}
return;
}
throw UnimplementedError("Undefined behavior for message: $message");
} static void _isolateEntry(dynamic message) {
  // 在子线程里面
SendPort sendPort;
final receivePort = ReceivePort(); receivePort.listen((dynamic message) async {
if (message is _Request) {
print('子线程收到:${message.message}');
sendPort.send(_Response.ok(message.requestId, '处理后的消息'));
return;
}
}); if (message is SendPort) {
sendPort = message;
sendPort.send(receivePort.sendPort);
return;
}
}
} class _Request {
/// The ID of the request so the response may be associated to the request's future completer.
final Capability requestId; /// The actual message of the request.
final dynamic message; const _Request(this.requestId, this.message);
} class _Response {
/// The ID of the request this response is meant to.
final Capability requestId; /// Indicates if the request succeeded.
final bool success; /// If [success] is true, holds the response message.
/// Otherwise, holds the error that occured.
final dynamic message; const _Response.ok(this.requestId, this.message) : success = true; const _Response.error(this.requestId, this.message) : success = false;
}

Flutter 多线程实现的更多相关文章

  1. Android开发如何准备技术面试(含Android面试押题)

    今年毋庸置疑是找工作的寒冬,每一个出来找工作的同学都是值得尊敬的.现在找工作,虽然略难,但是反过来看也会逼迫我们成为更加优秀的自己. 但是不管是旺季还是寒冬,有一些优秀的同学找工作还是挺顺利的.所以说 ...

  2. 双非本科字节跳动Android面试经验和心得体会分享(已拿offer)

    新人报道,没有什么可分享的,就记录一些自己求职的体会和心得. 我是在校招补录的时候参加了今日头条的招聘,岗位是Android开发,最后成功拿到了入场券.但是这也丝毫不值得骄傲,大家都知道:技术日新月异 ...

  3. 2579页阿里P8Android学习笔记在互联网上火了,完整版开放下载

    笔记作者:来自于阿里P8级大神: Mark 笔记特点:条理清晰,理论+实战+源码,含图像化表示更加易懂. 内容概要:Android 相关,性能优化,Java 相关,Kotlin 相关,网络相关,插件化 ...

  4. 2020年!最全Android大厂面试真题合集(附答案)

    这份Android面试真题涵盖了图片,网络和安全机制,网络,数据库,插件化.模块化.组件化.热修复.增量更新.Gradle,架构设计和设计模式,Android Framework .Android优秀 ...

  5. 说实话,Android开发月薪3W,谁不酸呢?

    近期有个网友在某匿名区晒字节跳动Offfer,毕业一年月薪3W,引发众多读者羡慕,纷纷留言酸了.酸了.但进大厂的要求还是蛮高的,需要在技术实力上有一定的积累,今天给大家分享一份高质量笔记, 助力大家技 ...

  6. Flutter 实现原理及在马蜂窝的跨平台开发实践

    一直以来,跨平台开发都是困扰移动客户端开发的难题. 在马蜂窝旅游 App 很多业务场景里,我们尝试过一些主流的跨平台开发解决方案, 比如 WebView 和 React Native,来提升开发效率和 ...

  7. Flutter学习一

    包管理 依赖本地包 dependencies: pkg1: path: ../../code/pkg1 依赖git包 dependencies: pkg1: git: url: git://githu ...

  8. Flutter中通过https post Json接收Json

    Flutter 已然成为炙手可热前端框架.若问跨平台到底有多香,自然是要多香有多香.今天我就分享这些天研究Flutter http连接和json格式转换的内容,小弟对Flutter也是小白一名,如有错 ...

  9. Flutter 简介(事件、路由、异步请求)

    1. 前言 Flutter是一个由谷歌开发的开源移动应用软件开发工具包,用于为Android和iOS开发应用,同时也将是Google Fuchsia下开发应用的主要工具.其官方编程语言为Dart. 同 ...

  10. iOS播放器、Flutter高仿书旗小说、卡片动画、二维码扫码、菜单弹窗效果等源码

    iOS精选源码 全网最详细购物车强势来袭 一款优雅易用的微型菜单弹窗(类似QQ和微信右上角弹窗) swift, UITableView的动态拖动重排CCPCellDragger 高仿书旗小说 Flut ...

随机推荐

  1. #FFT#P4173 残缺的字符串

    题目 有一个长度为 \(m\) 的字符串 \(A\) 和 一个长度为 \(n\) 的字符串 \(B\), 它们有若干位置为通配符,现在问 \(B\) 的每一个后缀是否存在前缀为 \(A\). 分析 考 ...

  2. SQLite主键自增代码

    引用:https://blog.csdn.net/maowendi/article/details/81115401 insert into TubeRunInfo (UserName) values ...

  3. 驾考宝典携手HMS Core统一扫码服务,构建复杂场景中的流畅扫码体验

    "驾考宝典"是一款颇具人气的互联网综合驾照考试学习应用,通过强大的驾考功能,在手机移动端为学车学员提供从报名.学习到拿本的全方位驾考服务.作为一个专业的驾培平台,"驾考宝 ...

  4. win10上鼠标右键怎么进入cmd

    背景: 在win7上有个很好的功能,在文件夹空白区域,按住 " ctrl + 鼠标右键 " 可以直接打开 cmd 窗口 但是在win10上同样的操作方法,打开的窗口却是 power ...

  5. Grafana系列-统一展示-10-Explore Jaeger

    系列文章 Grafana 系列文章 Explore Jaeger 你可以通过Explore查询和显示 Jaeger 的 trace.有 3 种方法: Query by search Query by ...

  6. HarmonyOS数据管理与应用数据持久化(二)

    通过键值型数据库实现数据持久化 场景介绍 键值型数据库存储键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格.员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同 ...

  7. 浅析eTS的起源和演进

    原文:https://mp.weixin.qq.com/s/N2RPeboN8Fj0-8wBMZJ-7w,点击链接查看更多技术内容. 引言 Mozilla创造了JS,Microsoft创建了TS,Hu ...

  8. CRC报错查看

    前言 查看交换机接口是否有CRC报错,本案例以华三交换机为例. CRC是指循环冗余校验错 使用仪器测试链路.链路质量差或者线路光信号衰减过大会导致报文在传输过程中出错.如链路故障请更换网线或光纤. 与 ...

  9. ActiveMQ c# 系列——进阶实例(三)

    前言 前面介绍了基本的消费者和生产者,那么看下他们之间有什么其他的api. 正文 消费者设置等待时间 生产者生产了5条消息 改一下消费者. static void Main(string[] args ...

  10. 高云GOWIN下载出现No devices found咋办

    在使用GOWIN下载器下载会出现该类问题 No devices found错误. 原因如下: A . Windows10 系统会出现下载器通道顺序错误,所以要确保在 A 通道上. B.有一些 USB ...