网站正在维护中 模板/写文章在哪里发表挣钱
1 Isolate
1.1 什么是Isolate
1.1.1 概念
线程?异步?隔离?到底什么意思?
Isolate中文意思是隔离,从使用角度来说是Dart的线程,但是从本质虚拟机的实现角度来讲Isolate是一组封装。
isolate可以理解为dart中的线程,但它又不同于线程,准确的说应该叫做协程,协程最大的优势就是它具有极高的执行效率,因为携程中子程序的调用不需要线程的切换,所以对于线程数量越大的程序来说协程的优势就越明显。每个isolate都有自己独立的执行线程和事件循环,以及内存,所以isolate之间不存在锁竞争的问题,各个isolate之间通过消息通信。
1.1.2 图例
1.1.3 设计目的
首先说目前由移动端页面(包含Android、iOS、Web)构建的特性—树形结构构建布局、布局解析抽象、绘制、渲染,这一系列的复杂步骤导致必须在同一个线程完成。因为多线程操作页面UI元素会有并发的问题,有并发就必须要加锁,加锁就会降低执行效率。所以强制在同一线程中操作UI是最好的选择。况且在Flutter中,开发者面对的只有一个主Isolate,在Isolate中可以通过事件队列来实现异步(网络请求、文件IO)等。
1.1.4 说明
1.为了达到设计目的,采取隔离设计去掉锁的应用
2.锁去掉后,线程间的信息通信需要建立通信机制来完成,参考linux os 底层策略上来讲本质上就是走IO那套体系来完成
1.2 Isolate本质
1.1.1 图例
1.1.2 说明
Dart本身抽象了isolate和thread,实际上底层还是使用操作系统的提供的OSThread。
1.3 Isolate组成
1.3.1 Stack用于存放函数调用上下文和调用链路信息。
1.3.2 Heap用于存放对象,堆内存回收管理和java类似。
1.3.3 Queue用于存放异步回调,分为微事件队列(MicroTaskQueue)和微任务队列(EventQueue)。
1.3.4 EventLoop用于处理异步回调。
1.4 Isolate底层逻辑
1.4.1 说明
虽然在内存表现上,Isolate内存隔离性像是进程的特点。但是从实现上不可能把Isolate作为一个进程,因为进程太重了,每新建一个进程,内核系统都会为新进程创建独立的虚拟内存,保存进程相关的数据结构,并且进程切换效率比较低。所以从可行性上来说Isolate的本质应该是一个线程。也就是说Isolate是通过线程实现的。我们使用多个Isolate也就是使用多个线程,只不过与传统线程不同的是,Isolate之间内存不共享,但可以通过通信机制互通。
1.4.2 Isolate如何实现内存隔离
// vm/isolate.cc Isolate*
Isolate::InitIsolate(const char* name_prefix, IsolateGroup* isolate_group, const Dart_IsolateFlags& api_flags, bool is_vm_isolate) { Isolate* result = new Isolate(isolate_group, api_flags); ... Heap::Init(result, is_vm_isolate? 0 // New gen size 0; VM isolate should only allocate in old. : FLAG_new_gen_semi_max_size * MBInWords, (is_service_or_kernel_isolate ? kDefaultMaxOldGenHeapSize : FLAG_old_gen_heap_size) *MBInWords); ... }
从代码中可以看Isolate的堆内存也被区分为新生代和老年代两块区域,Dart虚拟机针对不同的区域执行不同的垃圾回收策略:
新生代采用复制清除算法,针对频繁创建销毁的页面控件对象,可以从内存层面实现快速分配和回收。
老年代采用标记清除和标记整理两种算法,来适应不同的内存回收场景,尽量保证UI的流畅性。
这里也就解释了Dart中内存分配模型,和高效垃圾的回收机制。
1.5 运行图例
1.6 Isolate模式
在dart中编写的代码分为两种类型
1.6.1 同步模式
即正常编写的代码。
BIO模式
1.6.2 异步模式
一些返回类型为Future和Stream的函数。
NIO模式
1.7 Isolate使用案例
1.7.1 常规使用
import 'dart:isolate';
void main(){ print("main begin"); Isolate.spawn((message) { print("匿名函数线程:$message"); }, "inner msg..."); Isolate.spawn(newThread1, "hello 1"); Isolate.spawn(newThread2, "hello 2"); Isolate.spawn(newThread3, "hello 3"); print("main end");
}
void newThread1(String msg){ print("Thread 1 msg:$msg");
}
void newThread2(String msg){ print("Thread 2 msg:$msg");
}
void newThread3(String msg){ print("Thread 3 msg:$msg");
}
1.7.2 isolate.spwanUri
//当前文件import 'dart:isolate';
///isolate spawnUri方式
void main() { print("main begin"); test1(); newThread(); test2(); print("main end");
}
void test1(){ print("test1.....");
}
void test2(){ print("test2.....");
}
///参数的定义可以随意,参数中接收的SendPort是需要通信的发送端口
@sendPort
void newThread(){ print("新线程....."); ReceivePort receivePort = ReceivePort(); SendPort sendPort = receivePort.sendPort; Isolate.spawnUri(Uri(path: "./isolate_spawnUri_task.dart"),["msg1","msg2","msg3"], sendPort); //监听 receivePort.listen((message) { print("主线程接收到来自子线程消息:${message}"); switch(message[1]){ case 0: //子线程正在处理初始化数据... print("接收到初始化消息"); break; case 1: //子线程异步数据正在处理中.. print("接收到处理中状态消息"); break; case 2: //子线程数据处理完整 print("接收到任务完成消息"); receivePort.close(); break; } });
}//目标文件import 'dart:isolate';
import 'dart:io';
///isolate spawnUri方式
void main(List<String> args,SendPort sendPort) { print("isolate_spawnUri_task.dart begin"); print("接收到相关参数:$args"); sendPort.send(["开始执行异步操作",0]); sleep(Duration(seconds: 2)); sendPort.send(["加载数据中...",1]); sleep(Duration(seconds: 2)); sendPort.send(["异步任务完成",2]); sleep(Duration(seconds: 2)); print("isolate_spawnUri_task.dart end");
}
1.8 Isolate通信
1.8.1 说明
创建Isolate时需要指定一个接收端口(ReceivePort)的发送端口(SendPort),调用者可以通过这个发送端口发送数据到其他的Isolate中ReceivePort的listen中,这种机制被称为消息传递(message passing)
既然是内存隔离的,那么在调用者所在Isolate发送的消息数据是怎么传递到接收者所在的Isolate中的呢?也就是说Isolate通信的底层逻辑是什么呢?
答案是map_变量,map_是一个Hash列表。是在Dart虚拟启动时初始化的,所以map_变量是存在于Dart虚拟机所属内存的,而这块内是各个Isolate共享的
1.8.2 通信
import 'dart:isolate';///isolate 通信 - 单向
void main() async{print("main begin");ReceivePort receivePort = ReceivePort();Isolate.spawn(newThread,["你好",receivePort.sendPort]);//方案1:通过listen进行监听// receivePort.listen((message) {// print("listen方式-主线程接收到消息:$message");// });//方案2:通过 await关键字与async关键字建立阻塞通道var msg = await receivePort.first;//上面这两种方案上只选选择一种处理//原因:这里dart对于数据的等待接收,我们可以看做为socket的BIO与NIO//listen方案实际上就是利用select,epoll这种方案在进行循环监听//await 就是read的阻塞式等待print("await方式-主线程接收到消息:$msg");print("main end");
}///参数的定义可以随意,参数中接收的SendPort是需要通信的发送端口
///@sendPort
void newThread(var message){String msg = message[0];SendPort sendPort = message[1];print("通过参数传递的数据1:$msg");//通过传递过来的sendPort给主线程回消息sendPort.send("这个是子线程给主线程回的消息!!!");
}
1.8.3 为什么将Isolate设计成隔离的
1、首先说目前由移动端页面(包含Android、iOS、Web)构建的特性—树形结构构建布局、布局解析抽象、绘制、渲染,这一系列的复杂步骤导致必须在同一个线程完成。**因为多线程操作页面UI元素会有并发的问题,有并发就必须要加锁,加锁就会降低执行效率。所以强制在同一线程中操作UI是最好的选择。**况且在Flutter中,开发者面对的只有一个主Isolate,在Isolate中可以通过事件队列来实现异步(网络请求、文件IO)等。所以不需要再使用其他线程完成异步。
2、每当有页面交互时,必定会引起布局变化而重新绘制,这个过程会有频繁的大量的UI控件的创建和销毁,这就涉及到了耗时内存分配和回收。而这些较短生命周期的对象是存放在堆内存的新生代的,当虚拟机回收新生代内存时是要stop the world的,在Android或iOS中,各个线程共用一块堆内存,当非UI线程频繁申请、释放内存时也会触发垃圾回收,所以会间接影响UI线程的运行。
Dart为了解决这个问题,就每个Isolate(看做线程)分配各自的一块堆内存,并且独自管理内。这样的策略使得内存的分配和回收变得简单高效,并且不受其他Isolate的影响。
1.9 总结
1、Dart中向应用层提供了线程的封装——Isolate。应用层是不能创建线程的,只能使用Isolate
2、Isolate与传统的线程不同的是,内存隔离
3、Isolate设计成隔离的,是出于移动端页面UI构建特性考虑。第一点,UI绘制必须在同一线程内完成,所以强制同一线程是最好的选择。第二点,传统的线程内存共享,其他线程频繁的申请释放内存会触发垃圾回收,间接影响UI线程运行
2 Dart io
2.1 说明
2.2 将文件作为文本读取:
Future<void> main() async {var config = File('config.txt');// Put the whole file in a single string.var stringContents = await config.readAsString();print('The file is ${stringContents.length} characters long.');// Put each line of the file into its own string.var lines = await config.readAsLines();print('The file is ${lines.length} lines long.');
}
2.3 将文件作为二进制读取:
readAsBytes()
的调用返回一个Future,该函数在可用时提供结果Future<void> main() async {var config = File('config.txt');var contents = await config.readAsBytes();print('The file is ${contents.length} bytes long.');
}
2.4 错误处理
Future<void> main() async { var config = File('config.txt'); try { var contents = await config.readAsString(); print(contents); } catch (e) { print(e); }
}
2.5 用Stream读取文件:
import 'dart:io';
import 'dart:convert';Future<void> main() async {var config = File('config.txt');Stream<List<int>> inputStream = config.openRead();var lines = utf8.decoder.bind(inputStream).transform(const LineSplitter());try {await for (final line in lines) {print('Got ${line.length} characters from stream');}print('file is now closed');} catch (e) {print(e);}
}
2.6 写文件
var logFile = File('log.txt');
var sink = logFile.openWrite();
sink.write('FILE ACCESSED ${DateTime.now()}\n');
await sink.flush();
await sink.close();
var sink = logFile.openWrite(mode: FileMode.append)
add(List<int> data)
。2.7 列出目录中的文件
Future<void> main() async {var dir = Directory('tmp');try {var dirList = dir.list();await for (final FileSystemEntity f in dirList) {if (f is File) {print('Found file ${f.path}');} else if (f is Directory) {print('Found dir ${f.path}');}}} catch (e) {print(e.toString());}
}
2.8 其他常用方法
相关文章:

【Flutter入门到进阶】Dart进阶篇---Dart多线程异步原理
1 Isolate 1.1 什么是Isolate 1.1.1 概念 线程?异步?隔离?到底什么意思? Isolate中文意思是隔离,从使用角度来说是Dart的线程,但是从本质虚拟机的实现角度来讲Isolate是一组封装。 isolate可以理解为dar…...

WEB系列(二)-----------XSS
XSS原理及基础 定义 恶意攻击者会往Web页面里插入JS代码,当用户点击网页时.镶嵌的JS代码就会执行,从而达到恶意的特殊目的. 原因 程序对输入和输出的控制不够严格,导致payload输出到前段时被浏览器当做有效代码执行从而产生危害。 分类 存储型反射型DOM型 测…...

[python入门㊾] - python异常中的断言
目录 ❤ 断言的功能与语法 ❤ 常用断言 ❤ 常用的断言表达方式 ❤ 异常断言 ❤ 正则断言 ❤ 检查断言装饰器 ❤ 断言的功能与语法 Python assert(断言)用于判断一个表达式,在表达式条件为 False 的时候触发异常 断言可以在条件…...

一文告诉你什么是财务数据治理?
大家好,我是梦想家Alex,今天是周末,就不给大家分享技术文了~应出版社老师推荐,文末给大家送几本DAMA中国主席力荐,20位行业专家历时2年共同打造的《财务数据治理实战》,将数据治理理论应用于财务…...

MySQL数据库调优————ORDER BY语句
ORDER BY调优的核心原理,原则是利用索引的有序性跳过排序环节 关于ORDER BY语句的一些尝试 我们使用employees表进行尝试,索引情况如下 在执行计划的结果中,Extra里如果存在,Using filesort则表示,排序没有使用到索…...

Linux命令之grep
Linux grep是一个非常强大的文本搜索工具。按照给定的正则表达式对目标文本进行匹配检查,打印匹配到的行。grep命令可以跟其他命令一起使用,对其他命令的输出进行匹配。 grep语法如下: grep [options] [pattern] content 文本检索 grep可以对…...

一起学 pixijs(4):如何绘制文字md
大家好,我是前端西瓜哥,今天我们来学 pixijs 如何绘制文字。pixijs 版本为 7.1.2。 使用原生的 WebGL 来绘制文字是非常繁琐的,pixijs 对此进行了高层级的封装,提供了 Text 类和 BitMapText 类来绘制文字。 Text 最基本的写法&…...

mac m1设备上安装Qt并使用qt编程遇到的问题以及解决方式
# 简介: 首先在M1平台上的程序可以看到有两种架构,分别是intel的(x86-64)和苹果的m1(arm64架构),根据苹果的介绍,当在m1上面运行intel程序的时候使用的是转译的方式运行的ÿ…...

tensorflow 学习笔记(二):神经网络的优化过程
前言: 学习跟随 如何原谅奋力过但无声的 tensorflow 笔记笔记。 本章主要讲解神经网络的优化过程:神经网络的优化方法,掌握学习率、激活函数、损失函数和正则化的使用,用 Python 语言写出 SGD、Momentum、Adagrad、RMSProp、Ada…...

【Java】《Java8 实战》 CompletableFuture 学习
文章目录前言1. 并发(Concurrent) 和 并行(Parallel)1.1 并发的来源1.2 并发技术解决了什么问题2. 并行的来源2.1 并行解决了什么问题3. CompletableFuture 简介4. CompletableFuture 简单应用5. CompletableFuture 工厂方法的应用6. CompletableFuture join() 方法7. 使用 Par…...

Vue3之条件渲染
1.何为条件渲染 条件渲染就是在指定的条件下,渲染出指定的UI。比如当我们显示主页的时候,应该隐藏掉登录等一系列不相干的UI元素。即UI元素只在特定条件下进行显示。而在VUE3中,这种UI元素的显示和隐藏可以通过两个关键字,v-if 和…...

将Nginx 核心知识点扒了个底朝天(四)
为什么 Nginx 不使用多线程? Apache: 创建多个进程或线程,而每个进程或线程都会为其分配 cpu 和内存(线程要比进程小的多,所以 worker 支持比 perfork 高的并发),并发过大会榨干服务器资源。 Nginx: 采用…...

设计模式之工厂模式
文章の目录一、什么是工厂模式二、工厂模式有什么用?三、应用场景四、示例1、用字面量的方式创建对象2、使用工厂模式创建对象参考写在最后一、什么是工厂模式 工厂模式是一种众所周知的设计模式,广泛应用于软件工程领域,用于抽象创建特定对…...

80.链表-由来
链表是怎么发展来的 线性表:是n个具有相同特性的数据元素的有限序列。 链表:具有线性存储结构的线性表。 为什么需要使用链表?(链表是如何被设计出来的) 程序开发最重要的部分是如何在项目程序中找到一种合适的、好…...

元胞自动机
文章目录前言文献阅读摘要主要贡献方法框架实验结论元胞自动机元胞自动机是什么?构成及规则案例及代码实现总结前言 This week,the paper proposes a Multi-directional Temporal Convolutional Artificial Neural Network (MTCAN) model to impute and forecast P…...

设计模式之各种设计模式总结与对比
目录1 目标2 定位3 一句话归纳设计原则4 G0F 23种设计模式简介5 设计模式使用频次总结6 —句话归纳设计模式7 设计模式之间的关联关系和对比1 目标 1、 简要分析GoF 23种设计模式和设计原则,做整体认知。 2、 剖析Spirng的编程思想,启发思维,为之后深入学习Spring…...

JAVA练习55- Fizz Buzz
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-Fizz Buzz 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 2月19日练习…...

LeetCode笔记:Biweekly Contest 98
LeetCode笔记:Biweekly Contest 98 1. 题目一 1. 解题思路2. 代码实现 2. 题目二 1. 解题思路2. 代码实现 3. 题目三 1. 解题思路2. 代码实现 4. 题目四 比赛链接:https://leetcode.com/contest/biweekly-contest-98 1. 题目一 给出题目一的试题链接如…...

HNUCM-《算法分析与设计》期末考试考前复习题
问题 A: X星人的地盘题目描述一天,X星人和Y星人在一张矩形地图上玩抢地盘的游戏。X星人每抢到一块地,在地图对应的位置标记一个“X”;Y星人每抢到一块地,在地图对应的位置标记一个“Y”;如果某一块地无法确定其归属则标…...

算法导论【分治思想】—大数乘法、矩阵相乘、残缺棋盘
这里写自定义目录标题分治法概述特点大数相乘问题分治算法矩阵相乘分治算法残缺棋盘分治算法分治法概述 在分而治之的方法中,一个问题被划分为较小的问题,然后较小的问题被独立地解决,最后较小问题的解决方案被组合成一个大问题的解决。 通常…...

Java【七大排序】算法详细图解,一篇文章吃透
文章目录一、排序相关概念二、七大排序1,直接插入排序2,希尔排序3,选择排序4,堆排序5,冒泡排序5.1冒泡排序的优化6,快速排序6.1 快速排序的优化7,归并排序三、排序算法总体分析对比总结提示&…...

Autosar OS IOC
Inter-OS-Application Communicator 背景和基本原理General purposeIOC functionalityCommunicationNotificationIOC interface背景和基本原理 The IOC implementation shall be part of the Operating System IOC和操作系统紧密相关,是操作系统实现的一部分 The IO…...

记录一次Binder内存相关的问题导致APP被杀的BUG排查过程
事情的起因的QA压测过程发生进程号变更,怀疑APP被杀掉过,于是开始看日志 APP的压测平台会上报进程号变更时间点,发现是在临晨12:20分,先大概确定在哪个日志文件去找关键信息一开始怀疑是crash,然后就在日志…...

设计模式(十)----结构型模式之适配器模式
1、概述 如果去欧洲国家去旅游的话,他们的插座如下图最左边,是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑,手机在当地不能直接充电。所以就需要一个插座转换器,转换器第1面插入当地的插座,第2面…...

【数据结构】——队列
文章目录前言一.什么是队列,队列的特点二、队列相关操作队列的相关操作声明队列的创建1.队列的初始化2.对队列进行销毁3.判断队列是否为空队列4.入队操作5.出队操作6.取出队头数据7. 取出队尾数据8.计算队伍的人数总结前言 本文章讲述的是数据结构的特殊线性表——…...

Android OTA升级常见问题的解决方法
1.1 多服务器编译 OTA 报错 Android7 以后引入了 jack-server 功能,也导致在公共服务器上 编译 Android7 以上的版本时,会出现 j ack-server 报错问题。 在多用户服务器上 编译 dist 时 会出现编译过程中 会将 port_service 和 port_admin 改为 默认的 …...

说说Hibernate
当你在实战项目中需要用到SSH时, 如果你之前只用过Mybatis那自然是不能解决问题的, 因为在很多银行类金融类项目中你可能会使用到Hibernate, 那么关于Hibernate你应该要了解什么呢, 本篇文章就以学习Hibernate框架为目的, 巩固在工作中可能需要用到的这种ORM技术, 同时也欢迎家…...

目标检测论文阅读:DETR算法笔记
标题:End-to-End Object Detection with Transformers 会议:ECCV2020 论文地址:https://link.springer.com/10.1007/978-3-030-58452-8_13 官方代码:https://github.com/facebookresearch/detr 作者单位:巴黎第九大学、…...

Golang sync.Once 源码浅析
本文分析了Golang sync.Once 源码,并由此引申,简单讨论了单例模式的实现、 atomic 包的作用和 Java volatile 的使用。 sync.Once 使用例子 sync.Once 用于保证一个函数只被调用一次。它可以用于实现单例模式。 有如下类型: type instanc…...

C++面向对象(上)
文章目录前言1.面向过程和面向对象初步认识2.引入类的概念1.概念与用法2.类的访问限定符及封装3.类的作用域和实例化4.类的大小计算5.this指针3.总结前言 本文将对C面向对象进行初步介绍,引入类和对象的概念。围绕类和对象介绍一些基础知识,为以后深入学…...