当前位置: 首页 > news >正文

Flutter多线程

下面,我们来了解一下 Flutter 中的多线程(或称异步处理)机制。

首先要明确一个核心概念:Dart 是单线程的。这意味着你的 Flutter 应用默认只有一个执行线程(通常称为 UI 线程或主 Isolate)。所有你写的代码,包括 UI 渲染、用户交互、网络请求等,默认都运行在这个线程上。

如果在这个唯一的线程上执行耗时操作(如大量计算、网络请求、文件读写),就会导致界面卡顿甚至无响应,因为线程被阻塞,无法处理渲染和用户输入。

为了解决这个问题,Dart 并没有采用传统的多线程(Thread)模型,而是使用了基于事件循环(Event Loop) 和 异步操作(Async/Await) 的机制,并提供了 Isolate 来实现真正的并行执行。

一、异步操作(Async/Await)和事件循环(Event Loop)

这是处理 I/O 密集型任务(如网络请求、数据库操作)的首选方式。它不会创建新线程,但能避免阻塞主线程。

1. 核心原理:Event Loop

Dart 有一个永不停止的循环,叫做事件循环。它从一个队列(Event Queue)中不断地取出事件(如点击事件、网络返回、文件读取完成等)并执行它们对应的回调函数。

当你调用一个异步函数(如 Future.delayedhttp.get)时:

​​​​​​​
  1. 这个函数会立刻返回一个 Future 对象,但函数内部的耗时操作(如等待网络响应)会被交给系统底层去执行(底层可能是用线程池实现的,但这部分对 Dart 代码是透明的)。

  2. 主线程不会被阻塞,继续执行后续的同步代码。

  3. 当系统底层的操作完成后,会将一个“完成”的事件和对应的回调函数放入 Event Queue 中。

  4. 事件循环会从队列中取出这个事件,并执行回调函数(即 then 或 await 之后的代码)。

2. 如何使用:Async/Await 和 Future

Future 代表一个异步操作的结果(可能完成也可能未完成)。async 和 await 关键字让你可以用同步代码的风格来编写异步代码,提高可读性。

示例:网络请求:

// 这是一个异步函数,会立即返回一个 Future<String>
Future<String> fetchUserOrder() async {// await 会等待这个 Future 完成,但不会阻塞主线程// 在等待期间,主线程可以去处理其他事件(如渲染UI)final order = await http.get(Uri.parse('https://api.example.com/order'));// 当网络请求完成,事件循环会回到这里继续执行return order.body;
}void main() {print('开始获取订单...');fetchUserOrder().then((order) {// then 里的回调会在 Future 完成后被事件循环执行print('订单是:$order');});// 这行代码会在 fetchUserOrder 等待时立即执行print('等待订单中...');
}// 输出顺序:
// 开始获取订单...
// 等待订单中...
// (一段时间后)订单是:拿铁一杯

适用场景:I/O 操作,如网络请求、数据库访问、文件读写等。这些操作本身不需要 Dart 线程去等待,而是由操作系统去处理。

二、 Isolate(隔离)

对于真正的 CPU 密集型计算(如图像处理、加密解密、复杂JSON解析、大规模计算),仅仅使用异步是不够的。因为这些计算确实需要占用大量的 CPU 时间,即使在事件循环中,它们也会阻塞主线程,导致UI卡顿。这时就需要 Isolate

1. 核心原理

​​​​​​​​​​​​​​
  • 独立的内存空间:每个 Isolate 都有自己的内存和事件循环。Isolate 之间不共享内存。它们之间的通信只能通过传递消息(Passing Messages) 来完成,这避免了传统多线程中复杂的锁竞争问题。

  • 真正的并行:在多核CPU设备上,不同的 Isolate 可以被调度到不同的核心上同时运行,实现真正的并行计算。

2. 如何使用

Dart 提供了两种主要方式创建 Isolate:Isolate.spawn 和 compute 函数。

方式一:使用 compute 函数(推荐)

compute 是 Flutter 提供的一个工具函数,它简化了创建 Isolate 并与主 Isolate 通信的过程。它非常适合执行一个独立的、耗时的函数。

// 一个耗时的函数,它将在新的 Isolate 中执行
// 注意:这个函数必须是顶层函数或静态方法,不能是实例方法
int expensiveCalculation(int number) {int result = 0;for (int i = 0; i < number; i++) {result += i;}return result;
}void main() async {print('开始计算...');// 使用 compute 将函数和参数派送到新的 Isolate// 函数执行完毕后,结果会通过 Future 返回final result = await compute(expensiveCalculation, 1000000000);print('计算结果:$result');
}

方式二:使用 Isolate.spawn(更灵活,更复杂)

当你需要更复杂的通信(如多次来回传递消息)时,需要使用 Isolate.spawn 和 SendPort

import 'dart:isolate';// 新 Isolate 的入口函数
void isolateEntry(SendPort mainSendPort) async {// 创建一个端口来接收来自主 Isolate 的消息final receivePort = ReceivePort();// 将自己的 SendPort 发送给主 Isolate,以便主 Isolate 可以回消息mainSendPort.send(receivePort.sendPort);// 监听来自主 Isolate 的消息receivePort.listen((message) {if (message is int) {// 执行计算final result = expensiveCalculation(message);// 将结果发送回主 IsolatemainSendPort.send(result);}});
}void main() async {final receivePort = ReceivePort();print('开始计算...');// 创建新的 Isolateawait Isolate.spawn(isolateEntry, receivePort.sendPort);// 等待新 Isolate 发来的它的 SendPortfinal SendPort childSendPort = await receivePort.first;// 向新 Isolate 发送消息(要计算的数字)childSendPort.send(1000000000);// 等待新 Isolate 返回的结果receivePort.listen((message) {if (message is int) {print('计算结果:$message');receivePort.close(); // 通信完成后关闭端口}});
}

适用场景:CPU 密集型任务,这些任务需要大量计算,会长时间占用 CPU。

三、总结与对比

特性Async/Await + FutureIsolate
核心事件循环,单线程多线程,真正的并行
内存共享内存不共享内存,通过消息传递数据
开销开销极小开销较大(每个 Isolate 约 >100KB 内存)
通信简单,直接通过变量复杂,必须通过 SendPort/ReceivePort 传递消息
适用场景I/O 密集型任务(网络、文件、数据库)CPU 密集型任务(大量计算、图像处理)
代码示例await http.get(...)compute(heavyFunction, arg)

最佳实践

  1. 默认使用 Async/Await:对于绝大多数异步操作(如网络请求),这是最佳选择。

  2. 谨慎使用 Isolate:仅在处理真正耗时的 CPU 计算时使用。创建和通信的开销决定了它不应被滥用。

  3. 优先使用 compute 函数:如果你的任务可以抽象成一个简单的函数调用,使用 compute 能极大简化代码。

  4. 注意数据传输成本:在 Isolate 之间传递的数据会被深度复制(Deep Copy)。传递非常大的对象(如图片数据)可能会有性能问题。可以考虑将数据转移到新的 Isolate 中处理,而不是来回传递。

通过结合 异步编程(Async/Await) 和 Isolate,Flutter 应用可以既保持流畅的UI响应,又能高效地处理各种耗时任务。


文章转载自:

http://CIuvZfNm.wchcx.cn
http://Tg1Kprqe.wchcx.cn
http://Utjtq7R8.wchcx.cn
http://K40QSaaU.wchcx.cn
http://FlhkkTPW.wchcx.cn
http://A60yfMX4.wchcx.cn
http://ELRxEzP0.wchcx.cn
http://Lc9wWFR3.wchcx.cn
http://msniCQRK.wchcx.cn
http://mKOqTdP8.wchcx.cn
http://QExXFDF4.wchcx.cn
http://xss0kgnI.wchcx.cn
http://KTvGKcdj.wchcx.cn
http://pRozL8Pt.wchcx.cn
http://LTNlelHV.wchcx.cn
http://kB9ZLxlL.wchcx.cn
http://GJSDobJE.wchcx.cn
http://3UzXaxKY.wchcx.cn
http://8FK1zr5J.wchcx.cn
http://UXlNMwOT.wchcx.cn
http://fZDHyzcM.wchcx.cn
http://DcHi9j8M.wchcx.cn
http://wpXxg1Pe.wchcx.cn
http://sLjbjjj5.wchcx.cn
http://cVt24YnL.wchcx.cn
http://GLNKuxkM.wchcx.cn
http://juD582wT.wchcx.cn
http://5G1vTpUo.wchcx.cn
http://FQ99YAKO.wchcx.cn
http://QZtfawE4.wchcx.cn
http://www.dtcms.com/a/377371.html

相关文章:

  • 如何在高通跃龙QCS6490 Arm架构上使用Windows 11 IoT企业版?
  • JavaScript 对象说明
  • CMake目标依赖关系解析
  • 小型企业常用的元数据管理工具
  • 论文AI写作哪个软件好?实测对比5款热门AI写作工具
  • PostgreSQL 内机器学习的关键智能算法研究
  • 12公里无人机图传模组:从模糊到超高清的飞跃,抗干扰能力全面升级
  • GitHub Actions中steps下面的Setup environment设置的环境变量不能在后面步骤使用问题处理
  • YOLOv5实战-GPU版本的pytorch虚拟环境配置
  • 苍穹外卖项目实战(day7-2)-购物车操作功能完善-记录实战教程、问题的解决方法以及完整代码
  • 【VsCode】离线状态下安装插件
  • 浏览器开发CEFSharp (十七)网页自定义下载—仙盟创梦IDE
  • Nodejs读取目录下面的文件
  • docker 重命名镜像
  • 「CTF」青少年CTF·雏形系统
  • 光子计算芯片实战:Lightmatter Passage互连架构性能评测
  • 实时多模态电力交易决策系统:设计与实现
  • 条码控件Aspose.BarCode教程:使用 C# 构建 Code11 条形码生成器
  • 分布式专题——7 Redis Stack扩展功能
  • QuestionPicture:一键批量改图,支持压缩图片
  • Prompt提示词(保姆级教程)
  • SSM病房管理信息系统o45h4(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • SpreadJS:让多源数据筛选排序如 Excel 般便捷高效
  • ARM内存映射与启动地址重映射机制解析
  • 如何使用 QuickAPI 快速连接 MySQL 数据库并发布 RESTful API
  • PAT 1104 Sum of Number Segments
  • LeetCode 热题 3.无重复字符的最长子串
  • 抓虫:unshared后执行命令dump
  • 自定义类型:结构体、枚举、联合
  • SnowPro Core Certification