文章目录

  • 简介
  • dart中的隔离机制
  • 生成一个Isolate
  • Isolate之间的交互
  • 一个例子
  • 总结

简介

之前介绍了很多dart中的异步编程技巧,不知道大家有没有发现一个问题,如果是在java的异步编程中,肯定会提到锁和并发机制,但是对于dart来说,好像从来没有听到多线程和并发的问题,这是为什么呢?

今天,给大家讲解一下dart中的隔离机制,大家就明白了。

dart中的隔离机制

dart是一个单线程的语言,但是作为一个单线程的语言,dart却支持Future,Stream等异步特性。这一切都是隔离机制和事件循环带来的结果。

首先看一下dart中的隔离机制。

所谓隔离指的是dart运行的一个特定的空间,这个空间拥有单独的内存和单线程的事件循环。

如下图所示:

在java或者c++等其他语言中,多个线程是共享内存空间的,虽然带来了并发和数据沟通的方便途径,但是同时也造成了并发编程的困难。

因为我们需要考虑多线程之间数据的同步,于是额外多出了很多锁的机制,详细了解或者用过的人应该都会很烦恼。

多线程最大的缺陷就是要求程序员的罗辑思维和编程技巧足够优秀,这样才能够设计出完美运行的多线程程序。

但是在dart中,这些都不是什么问题。dart中所有的线程都拥有自己的运行空间,这个线程的工作就是运行事件循环。

那么问题来了,主线程在处理事件循环,但是如果遇到了一个非常耗时的操作,该怎么办呢? 如果直接在主线程中运行,则可能会导致主线程的阻塞。

dart也充分考虑到了这个问题,所以dart提供了一个Isolate的类来对隔离进行管理。

因为dart程序本身就在一个Isolate中运行,所以如果在dart中定义一个Isolate,那么这个Isolate通常表示的是另外一个,需要和当前Isolate进行通信的Isolate。

生成一个Isolate

那么如何在当前的dart程序中生成一个Isolate呢?

Isolate提供了三种生成方法。

一个非常常用的是Isolate的工厂方法spawn:

  external static Future<Isolate> spawn<T>(void entryPoint(T message), T message,{bool paused = false,bool errorsAreFatal = true,SendPort? onExit,SendPort? onError,@Since("2.3") String? debugName});

spawn会创建一个新的Isolate,调用它需要传入几个参数:

entryPoint表示的是生成新Isolate的时候需要调用的函数。entryPoint接受一个message参数。通常来说message是一个SendPort对象,用于两个Isolate之间的沟通。

paused表示新生成的Isolate是否处于暂停状态,他相当于:

isolate.pause(isolate.pauseCapability)

如果后续需要取消暂停状态,则可以调用:

isolate.resume(isolate.pauseCapability)

errorsAreFatal 对应的是setErrorsFatal方法。

onExit对应的是addOnExitListener, onError对应的是addErrorListener。

debugName表示的是Isolate在调试的时候展示的名字。

如果spawn出错,则会抛出IsolateSpawnException异常:

class IsolateSpawnException implements Exception {/// Error message reported by the spawn operation.final String message;@pragma("vm:entry-point")IsolateSpawnException(this.message);String toString() => "IsolateSpawnException: $message";
}

spawn方法生成的是和当前代码一样的Isolate。如果想要使用不同的代码来生成,则可以使用spawnUri,通过传入对应的Uri地址,从而生成不一样的code。

external static Future<Isolate> spawnUri(Uri uri,List<String> args,var message,{bool paused = false,SendPort? onExit,SendPort? onError,bool errorsAreFatal = true,bool? checked,Map<String, String>? environment,@Deprecated('The packages/ dir is not supported in Dart 2')Uri? packageRoot,Uri? packageConfig,bool automaticPackageResolution = false,@Since("2.3")String? debugName});

还有一种方式,就是使用Isolate的构造函数:

Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});

它有三个参数,第一个参数是controlPort,代表另外一个Isolate的控制权,后面两个capabilities是原isolate的子集,表示是否有pause或者terminate的权限。

一般用法如下:

Isolate isolate = findSomeIsolate();
Isolate restrictedIsolate = Isolate(isolate.controlPort);
untrustedCode(restrictedIsolate);

Isolate之间的交互

所有的dart代码都是运行在Isolate中的,然后代码只能够访问同一个isolate内的class和value。那么多个isolate之间通信,可以ReceivePort和SendPort来实现。

先看下SendPort,SendPort是Capability的一种:

abstract class SendPort implements Capability

SendPort用于向ReceivePort发送message, message可以有很多类型,包括:

Null,bool,int,double,String,List,Map,TransferableTypedData,SendPort和Capability。

注意,send动作是立马完成的。

事实上,SendPort是由ReceivePort来创建的。一个ReceivePort可以接收多个SendPort。

ReceivePort是Stream的一种:

abstract class ReceivePort implements Stream<dynamic>

作为Stream,它提供了一个listen用来处理接收到的消息:

  StreamSubscription<dynamic> listen(void onData(var message)?,{Function? onError, void onDone()?, bool? cancelOnError});

一个例子

讲了那么多原理,有的同学可能会问了,那么到底怎么用呢?

例子来了:

import 'dart:isolate';var isolate;void entryPoint(SendPort sendPort) {int counter = 0;sendPort.send("counter:$counter");
}
void main() async{final receiver = ReceivePort();receiver.listen((message) {print( "接收到消息 $message");});isolate = await Isolate.spawn(entryPoint, receiver.sendPort);
}

在主线程中,我们创建了一个ReceivePort,然后调用了它的listen方法来监听sendPort发过来的消息。

然后spawn出一个新的Isolate,这个Isolate会在初始化之后,调用entryPoint方法。

在这个entryPoint方法中又使用sendPort向ReceivePort发送消息。

最终运行,打印:

接收到消息 counter:0

总结

以上就是dart中的隔离机制和Isolate的使用。

本文已收录于 http://www.flydean.com/25-dart-isolates/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

dart系列之:dart优秀的秘诀-隔离机制相关推荐

  1. dart系列之:dart语言中的特殊操作符

    dart系列之:dart语言中的特殊操作符 文章目录 简介 普通操作符 类型测试操作符 条件运算符 级联符号 类中的自定义操作符 总结 简介 有运算就有操作符,dart中除了普通的算术运算的操作符之外 ...

  2. dart系列之:dart代码规范实践指南

    文章目录 简介 命名规则 import中的顺序 格式化 总结 简介 每种语言都有自己的代码风格,这种代码风格是跟语言特性息息相关的.如果在编码的过程中遵循这种统一的编码规则,会给我们的业务带来非常多的 ...

  3. dart系列之:dart中的异步编程

    文章目录 简介 为什么要用异步编程 怎么使用 Future 异步异常处理 在同步函数中调用异步函数 总结 简介 熟悉javascript的朋友应该知道,在ES6中引入了await和async的语法,可 ...

  4. dart系列之:dart语言中的变量

    文章目录 简介 dart中的变量 定义变量 变量的默认值 Late变量 常量 总结 简介 flutter是google在2015年dart开发者峰会上推出的一种开源的移动UI构建框架,使用flutte ...

  5. dart系列之:dart类中的泛型

    文章目录 简介 为什么要用泛型 怎么使用泛型 类型擦除 泛型的继承 泛型方法 总结 简介 熟悉JAVA的朋友可能知道,JAVA在8中引入了泛型的概念.什么是泛型呢?泛型就是一种通用的类型格式,一般用在 ...

  6. dart系列之:dart类的扩展

    文章目录 简介 使用extends 抽象类和接口 mixins 总结 简介 虽然dart中的类只能有一个父类,也就是单继承的,但是dart提供了mixin语法来绕过这样限制. 今天,和大家一起来探讨一 ...

  7. dart系列之:dart类中的构造函数

    文章目录 简介 传统的构造函数 命名构造函数 构造函数的执行顺序 重定向构造函数 Constant构造函数 工厂构造函数 总结 简介 dart作为一种面向对象的语言,class是必不可少的.dart中 ...

  8. dart系列之:dart语言中的异常

    文章目录 简介 Exception和Error Throw和catch Finally 总结 简介 Exception是程序中的异常情况,在JAVA中exception有checked Excepti ...

  9. dart系列之:dart语言中的函数

    文章目录 简介 函数的参数 main函数 匿名函数 闭包 函数的返回值 总结 简介 函数是所有编程语言都有的内容,不管是面向对象还是面向过程,函数都是非常重要的一部分.dart中的函数和java中的函 ...

最新文章

  1. 小白阶段如何学习Web前端知识
  2. EOS 智能合约源代码解读 (11)wrap合约“action_wrapper类”
  3. break和continue区别python_1、Python中break和continue的区别
  4. ACM——A + B Problem (4)
  5. [转]Google的60款开源项目
  6. 高通收购恩智浦为什么要中国批准?
  7. python从入门到放弃-掌握这个学习方法,让 Python 不再从入门到放弃
  8. win10 安装c语言无法启动,win10开机出现0xc0000098无法启动简单解决方法
  9. Oracle学习方法
  10. 项目管理的流程及生命周期
  11. 大数据分析-实验八 鸢尾花数据集分类
  12. ORL Character Recgnition
  13. 打通云主机实现局域网
  14. php 数独计算器,问题描述:数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字_题来了...
  15. 离线语音交互技术路线之语音合成(TTS)篇
  16. [文心大模型创意项目]还在愁没有头像?属于你的个人头像来了!
  17. 微信解除自定义表情150个上限?
  18. REST-Assured,接口自动化的 “瑞士军刀“- 断言篇
  19. 《重构:改善既有代码的设计》读书笔记(上)
  20. python文件操作练习题【学生成绩.txt】

热门文章

  1. TrackFormer解读
  2. php ajax 分页phpapi,ajax分页_php ajax分页代码
  3. assert()函数
  4. Shell case esac语句
  5. cocos2d-x初探学习笔记(1)--HelloWorld
  6. STL中map用法详解
  7. 使用Scrapy框架发送POST请求
  8. Python 中的url,Base64和MD5编码解码的使用
  9. Netty学习笔记(四)EventLoopGroup续篇
  10. JDK/Java 17 可能带来什么新特性?