【Flutter】Dart:Isolate
在 Dart 和 Flutter 中,所有的代码默认都运行在单一的线程(即主线程)上,这个线程也叫做 UI 线程。当进行耗时操作(如复杂计算或网络请求)时,如果不使用多线程处理,主线程会被阻塞,导致应用界面卡顿、无响应,影响用户体验。为了解决这个问题,Dart 提供了 Isolate,一种独立的执行单元,可以并行执行任务。
本教程将深入介绍 Dart 中的 Isolate,涵盖其含义、事件循环、消息传递机制以及如何在不同 Isolate 之间进行通信。
什么是 Isolate
在 Dart 中,Isolate 是一种独立的执行单元,它和线程的概念相似,但与传统的多线程不同。每个 Isolate 都拥有独立的内存堆和事件循环,因此 Isolate 之间不能直接共享内存,而是通过消息传递进行通信。由于隔离的内存管理,Isolate 能够有效避免多线程中的竞态条件和数据竞争问题。
单线程与 Isolate 的区别
-
单线程:Dart 默认在单一线程上运行任务。单线程模型避免了复杂的线程同步问题,但在处理耗时任务时会阻塞主线程,影响应用的响应性。
-
Isolate:Isolate 是独立的执行单元,能够并行处理任务。每个 Isolate 都有自己的内存空间,不与其他 Isolate 共享数据,因此不会出现线程竞争问题。
示例:传统单线程任务阻塞
void main() {print('Start');// 模拟耗时任务for (int i = 0; i < 1000000000; i++) {}print('End');
}
在上述代码中,耗时任务会阻塞主线程,导致应用无法响应用户操作。为了解决这种问题,可以使用 Isolate 来将任务移出主线程。
Isolate 的事件循环与并行执行
每个 Isolate 都有自己的 事件循环,负责管理消息队列并处理异步任务。Dart 中的异步操作(如 Future
和 Stream
)也都是通过事件循环来调度的。当一个 Isolate 接收到消息时,它会将消息放入事件队列,并在合适的时机进行处理。
如何创建 Isolate
可以通过 Isolate.spawn()
来创建新的 Isolate。该方法会启动一个新的 Isolate,并执行指定的任务。
示例:创建 Isolate
import 'dart:isolate';void isolateTask(String message) {print('Isolate received: $message');
}void main() {print('Main isolate: Start');// 启动新的 IsolateIsolate.spawn(isolateTask, 'Hello from Main isolate');print('Main isolate: End');
}
输出:
Main isolate: Start
Main isolate: End
Isolate received: Hello from Main isolate
在这个例子中,我们使用 Isolate.spawn()
创建了一个新的 Isolate,运行 isolateTask()
函数,同时将消息传递给新的 Isolate。可以看到主线程不会等待 Isolate 的完成,而是继续执行后续代码。
Isolate 之间的消息传递
由于 Isolate 之间不能共享内存,因此它们只能通过 消息传递 进行通信。Dart 提供了 SendPort
和 ReceivePort
来在不同 Isolate 之间传递消息。
ReceivePort
:接收消息的端口,类似于消息队列。SendPort
:发送消息的端口,通过SendPort
可以向另一个 Isolate 发送消息。
创建消息传递机制
首先需要在主 Isolate 创建一个 ReceivePort
,并将 SendPort
传递给新的 Isolate。新的 Isolate 可以通过 SendPort
发送消息,主 Isolate 使用 ReceivePort
来接收消息。
示例:主 Isolate 和子 Isolate 间的消息传递
import 'dart:isolate';void isolateTask(SendPort sendPort) {// 向主 Isolate 发送消息sendPort.send('Message from Isolate');
}void main() async {// 创建用于接收消息的 ReceivePortReceivePort receivePort = ReceivePort();// 启动新的 Isolate,并传递 SendPortawait Isolate.spawn(isolateTask, receivePort.sendPort);// 监听来自 Isolate 的消息receivePort.listen((message) {print('Main isolate received: $message');});
}
输出:
Main isolate received: Message from Isolate
在这个例子中,我们创建了一个 ReceivePort
,并将它的 SendPort
传递给新的 Isolate。子 Isolate 使用 sendPort.send()
发送消息,主 Isolate 则通过 receivePort.listen()
接收并处理消息。
Isolate 双向通信
除了子 Isolate 向主 Isolate 发送消息之外,主 Isolate 也可以向子 Isolate 发送消息。这需要双向的 SendPort
和 ReceivePort
,实现双向通信。
实现双向通信
在双向通信中,主 Isolate 和子 Isolate 都有各自的 SendPort
和 ReceivePort
,相互之间可以发送和接收消息。
示例:双向通信
import 'dart:isolate';// 子 Isolate 任务,接收消息并回复
void isolateTask(SendPort mainSendPort) {// 创建子 Isolate 的接收端口ReceivePort isolateReceivePort = ReceivePort();// 向主 Isolate 发送子 Isolate 的 SendPortmainSendPort.send(isolateReceivePort.sendPort);// 监听来自主 Isolate 的消息isolateReceivePort.listen((message) {print('Isolate received: $message');// 回复主 IsolatemainSendPort.send('Reply from Isolate');});
}void main() async {// 创建主 Isolate 的接收端口ReceivePort mainReceivePort = ReceivePort();// 启动子 Isolate,并传递主 Isolate 的 SendPortawait Isolate.spawn(isolateTask, mainReceivePort.sendPort);// 监听来自子 Isolate 的消息mainReceivePort.listen((message) {if (message is SendPort) {// 收到子 Isolate 的 SendPort,向其发送消息SendPort isolateSendPort = message;isolateSendPort.send('Hello from Main isolate');} else {print('Main isolate received: $message');}});
}
输出:
Isolate received: Hello from Main isolate
Main isolate received: Reply from Isolate
在这个示例中,主 Isolate 和子 Isolate 都有自己的 ReceivePort
和 SendPort
。主 Isolate 将自己的 SendPort
传递给子 Isolate,子 Isolate 通过该 SendPort
发送消息回复主 Isolate。实现了双向的通信。
Isolate 的常见使用场景
耗时计算
在复杂的计算任务(如图像处理、大数据计算等)中使用 Isolate 可以避免阻塞 UI 线程。
示例:耗时任务
import 'dart:isolate';// 耗时任务
void computeTask(SendPort sendPort) {int sum = 0;for (int i = 0; i < 100000000; i++) {sum += i;}sendPort.send(sum);
}void main() async {ReceivePort receivePort = ReceivePort();// 启动 Isolate 执行耗时任务await Isolate.spawn(computeTask, receivePort.sendPort);// 获取计算结果receivePort.listen((result) {print('Sum: $result');});
}
在这个例子中,计算任务被移到子 Isolate 中执行,主线程不会被阻塞,从而保证了应用的流畅性。
网络请求并发处理
通过 Isolate 可以并行处理多个网络请求,提升网络任务的处理效率。
总结
Isolate
是 Dart 中一种重要的并行执行机制,适用于需要处理复杂计算或长时间执行任务的场景。与传统的多线程不同,Isolate 之间通过消息传递进行通信,避免了数据竞争和线程同步问题。在 Flutter 开发中,合理使用 Isolate 可以提高应用的性能和用户体验,确保长时间任务不会阻塞主线程。
掌握 Isolate 的使用,包括事件循环、消息传递和双向通信,可以帮助你构建高性能、响应迅速的应用。在实际开发中,Isolate 主要用于耗时操作、并发任务以及后台数据处理等场景。
相关文章:

【Flutter】Dart:Isolate
在 Dart 和 Flutter 中,所有的代码默认都运行在单一的线程(即主线程)上,这个线程也叫做 UI 线程。当进行耗时操作(如复杂计算或网络请求)时,如果不使用多线程处理,主线程会被阻塞&am…...

微信小程序 页面间传递数据
在小程序中,给页面传递参数通常有以下几种方法: 通过URL传递参数: 在小程序中,可以在页面的路径后面添加参数,然后在页面的 onLoad 函数中获取这些参数。 // 在app.json中配置页面路径 "pages": [{"pat…...

前端_005_Nodejs
文章目录 npm包管理器cjs和mjsYarn包管理器 1.Node.js 是js的一个运行环境,从nodejs诞生后js代码不局限于只在浏览器中执行,此外还能再nodejs里写服务端,用js可以前后端全栈开发 2.Node.js不跟浏览器一样默认含有document,window对象…...

SpringCache缓存介绍
1.为什么需要缓存 前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果: 使用缓存是一个很…...

python实战(一)——iris鸢尾花数据集分类
一、任务背景 本文是python实战系列专栏的第一篇文章,我们将从分类开始由浅入深逐步学习如何使用python完成常规的机器学习/深度学习任务。iris数据集是经典的机器学习入门数据集,许多分类任务教程都会以这个数据集作为示例,它的数据量是150条…...

k8s-对命名空间资源配额
对k8s命名空间限制的方法有很多种,今天来演示一下很常用的一种 用的k8s对象就是ResourceQuota 一:创建命名空间 kubectl create ns test #namespace命名空间可以简写成ns 二: 对命名空间进行限制 创建resourcequota vim resourcequ…...

Failed to connect to github.com port 443
git push无法连接443端口 **问题1****方法一:取消代理设置**git命令 其他解决方案1. **设置 Git 使用 HTTP 而不是 HTTPS**2. **检查证书**3. **配置 Git 忽略 SSL 验证(不推荐)**4. **检查代理设置** 问题1 Failed to connect to github.com…...

【设计模式系列】简单工厂模式
一、什么是简单工厂模式 简单工厂模式(Simple Factory Pattern)是一种设计模式,其中包含一个工厂类,根据传入的参数不同,返回不同类的实例。这个工厂类封装了对象的创建逻辑,使得客户端代码可以从直接创建…...

给定一个正整数n随机生成n个字节即生成2n个十六进制数将其组成字符串返回secrets.token_hex(n)
【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 给定一个正整数n 随机生成n个字节 即生成2n个十六进制数 将其组成字符串返回 secrets.token_hex(n) [太阳]选择题 根据题目代码,执行的结果错误的是? import secrets …...

[Gtk] 工程
MediaPlayer 可执行文件工程 结构 . ├── BUILD ├── ButtonHelper.cpp ├── ButtonHelper.h ├── CMakeLists.txt ├── DrawingAreaHelper.cpp ├── DrawingAreaHelper.h ├── layout.ui └── main.cpp CMakeLists.txt # 1) cmake basic cmake_minimum_r…...

基于Multisim的汽车尾灯控制电路设计与仿真
假设汽车尾部左右量测各有3个指示灯(用发光二极管模拟)1. 汽车正常运行时指示灯全灭;2.右转弯时,右侧3个指示灯按右循环顺序点亮;.3. 左转弯时,左侧3个指示灯按左循环顺序点亮;4.临时刹车时所有…...

Leetcode 3326. Minimum Division Operations to Make Array Non Decreasing
Leetcode 3326. Minimum Division Operations to Make Array Non Decreasing 1. 解题思路2. 代码实现 题目链接:3326. Minimum Division Operations to Make Array Non Decreasing 1. 解题思路 这一题的话就是要看出来题中给出的operation的本质事实上就是将任意…...

redo文件误删除后通过逻辑备份进行恢复
问题描述 开发同事让在一个服务器上查找下先前库的备份文件是否存在,如果存在进行下恢复。翻了服务器发现备份文件存在,多愁了一眼竟翻到了该备份文件于2024.6.17日恢复过的日志,赶紧和开发沟通说2024.6.17号已经恢复过了为啥还要恢复&#x…...

7805的输出电压如何调整?
7805稳压集成电路的输出电压通常是固定的,标称为5V。然而,在实际应用中,可以通过一些方法调整其输出电压,尽管这些调整方法可能会使电路变得更加复杂或需要额外的元件。以下是几种可能的调整方法: 1. 使用不同型号的稳…...

git命令使用一览【自用】
git常见操作: git initgit remote add master【分支名字】 gitgits.xxxxx【仓库中获取的ssh链接或者http协议的链接】检查远程仓库是否链接成功。 git remote -v出现以下画面就可以git pull,git push了...

MES系列-报表和分析
MES系列-报表和分析 MES系列文章目录 ISA-95制造业中企业和控制系统的集成的国际标准-(1) ISA-95制造业中企业和控制系统的集成的国际标准-(2) ISA-95制造业中企业和控制系统的集成的国际标准-(3) ISA-95制造业中企业和控制系统的集成的国际标准-(4) ISA-95制造业中企业和控制…...

如何在分布式环境中实现高可靠性分布式锁
目录 一、简单了解分布式锁 (一)分布式锁:应对分布式环境的同步挑战 (二)分布式锁的实现方式 (三)分布式锁的使用场景 (四)分布式锁需满足的特点 二、Redis 实现分…...

Vue基础(4)
自定义指令 除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。在vue中使用directive来创建自定义指令 钩子函数 指令定义函数提供了几个钩子函数(可选): bind: 只调用一次,指令第一次绑定到元素时调用&…...

Redis高阶篇之Redis单线程与多线程
文章目录 0 前言1. 为什么Redis是单线程?1.1 Redis单线程1.2 为什么Redis3时代单线程快的原因1.3 使用单线程原因 2.为什么逐渐加入多线程呢?2.1 如何解决 3.redis6/7的多线程特性和IO多路复用入门3.1主线程和IO线程怎么协作完成请求处理的3.2 Unix网络编…...

【C++】STL——priority_queue优先级队列
目录 前言priority_queue的使用简单使用在OJ中的使用 priority_queue的模拟实现基本功能仿函数在这里插入图片描述 前言 上一节我们说了stack和queue这两种容器适配器,而priority_queue(优先级队列)同样也是属于容器适配器,它会优…...

大数据新视界 --大数据大厂之大数据在智慧城市建设中的应用:打造智能生活的基石
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

使用枚举来实现策略模式
使用很多if else的场景 public void save(String type,Object data){if("db".equals(type)){saveInDb(data);}else if("file".equals(type)){saveInFile(data);}else if("oss".equals(type)){saveInOss(data);}}使用枚举来解决 public enum Save…...

区块链技术原理
1. 引言 区块链的定义 区块链是一种分布式账本技术(Distributed Ledger Technology,DLT),其核心特征是通过密码学的方式将数据打包成一个个区块,按时间顺序依次相连,形成一个不可篡改、公开透明的链式数据…...

Spring Boot 接口数据加解密
今天聊下接口安全问题,涉及到接口的加密和解密 经常和外部单位接口调用梳理了相关技术方案,主要的需求点如下: 1,尽量少改动,不影响之前的业务逻辑 2,考虑到时间紧迫性,可采用对称性加密方式&…...

2018年计算机网络408真题解析
第一题: 解析:TCP/IP体系结构应用层常用协议及其相应的运输层协议 TCP协议是面向连接可靠数据传输服务,UDP无连接不可靠的数据传输服务,IP无连接不可靠的数据连接服务。 FTP协议,SMTP协议和HTTP协议使用TCP协议提供的面…...

Javascript 脚本查找B站限时免费番剧
目录 前言 脚本编写 脚本 前言 B站的一些番剧时不时会“限时免费”,白嫖党最爱,主打一个又占到便宜的快乐。但是在番剧索引里却没有搜索选项可以直接检索“限时免费”的番剧,只能自己一页一页的翻去查看,非常麻烦。 自己找限…...

YoloV10改进策略:主干网络改进|DeBiFormer,可变形双级路由注意力|全网首发
摘要 在目标检测领域,YoloV10以其高效和准确的性能而闻名。然而,为了进一步提升其检测能力,我们引入了DeBiFormer作为YoloV10的主干网络。这个主干网络的计算量比较大,不过,上篇双级路由注意力的论文受到很大的关注,所以我也将这篇论文中的主干网络用来改进YoloV10,卡多…...

C#学习笔记(一)
C#学习笔记(一) 简介第一章 上位机开发环境之 VS 使用和.NET 平台基础一、安装软件二、创建项目三、第一个Hello world四、解决方案与项目五、Debug 和 Release 的区别六、代码的生产过程七、CLR的其它功能 简介 C# .NET工控上位机开发 在工控领域&…...

MATLAB边缘检测
一、目的: 熟悉边缘检测原理,并运用matlab软件实现图像的canny边缘检测,体会canny边缘检测的优缺点。 二、内容: 编写matlab程序,实现对lena图像的边缘检测,输出程序运行结果。 三、原理或步骤&#x…...

Tortoise SVN 安装汉化教程(乌龟SVN)
1.首先下载 去官网下载 如果下载比较慢的,链接自取 https://pan.quark.cn/s/cb6f2eee3f90 2. 安装Tortoise SVN 无脑next到完成 最后到桌面右键 你就发现svn出来了,但是是英文的!!!! 像我这种英文不好的…...