有没有一种感觉,就我自己而言,Flutter
项目开发了好几个了,但是对这个 isolates
印象依旧很陌生,日常开发中好像很少见到它身影或者用到它,但真实情况是这样的吗?今天就来聊一聊它。
Flutter
中的 isolates
是什么?
在 Flutter
中,Isolates
(隔离区)是一种轻量级的并发执行单元,用于在单个进程中执行代码。与线程有点儿像,但是每个 Isolates
之间又是完全独立的,彼此之间没有共享内存。每个 Isolates
都有自己的内存堆,可以独立执行代码,处理任务,而不会受到其他 Isolates
的影响。它们之间只能通过消息传递进行通信。
我们可以通过 Isolate.current
来查看当前正在执行的 Isolate
Flutter
中有哪些 isolates
?
在 Flutter
中,主要有两种类型的 Isolates
Main Isolates
: 也称为UI
线程或UI Isolate
,启动应用程序时,Dart VM
会自动创建一个Isolate
实例并在其上运行您的“主”代码,相当于是Flutter
应用程序的主线程,负责处理用户界面和用户交互。在Main Isolate
中执行的代码通常包括构建UI
、处理用户输入等任务。打印Isolate.current.debugName
可以看到:Background Isolates
:运行在后台,可以用于执行耗时操作,如网络请求、长的JSON
解析、文件读取、计算密集型任务等。通过后台Background Isolates
,可以避免在主Isolate
中执行长时间运行的任务,从而保持应用程序的响应性。
默认情况下,Flutter
应用程序会在 Main Isolates
上完成所有工作,切处理速度很快,不会出现 UI
卡顿,但执行异常大的计算的时候,会出现 UI
卡顿,和原生开发一样,在子线程执行耗时操作,在 Flutter
中就需要将耗时操作放在辅助的 Isolates
中,也就是 Background Isolates
。
事件循环与页面卡顿
每个 Isolates
都有自己的内存和事件循环,事件循环是按照事件添加到事件队列的顺序来处理事件。在 Main Isolates
中,这些事件可以是用户的点击事件、函数执行和绘制视图到屏幕上等等。 为了更平滑的渲染视图,Flutter
底层会以 60次/每秒 向事件队列添加“绘制帧”事件(对于 60Hz 设备)。 如果这些事件没有及时处理,就会出现 UI
卡顿或者没有响应。
如果某个事件无法在两帧之间的时间(帧间隙)内完成时,最好将这个事件的执行放在其它的 Isolates
,用来确保 Main Isolates
每秒可以生成 60 帧。
Isolates
之间通信
创建一个新的 isolate
有两种方式,构造方法 Isolate(...)
和 静态方法 Isolate.spaw
。下面例子创建一个新的 isolate
每隔一秒向 Main Isolates
发送当前时间戳。
1 | Future<void> main() async { |
执行结果的 log
:
1 | Performing hot restart... |
isolate
消息传递的流程图如下:
实际上,Flutter
中Isolates
就是 Actor model
实现,Isolates
之间只能通过消息传递来相互通信,而且消息是通过复制的方式从发送 Isolate
传递到接收的 Isolate
,也就是说,当这个数据消息在接收的 Isolate
上发生变化的时候,发送 Isolate
的原数据不受影响。
SendPort.send
: 发送时生成可变消息的副本
传递的消息是不可变对象时 immutable objects
,如不可变的字符串,会发送对该对象的引用,而不是复制的对象,这样做也是为了获得更好的性能。不可变对象无法更新,也符合Actor model
的实现。
Isolate.exit
:发送对消息的引用
特殊情况就是当发送方Isolate
在发送完消息后就销毁了,会将消息的所有权传递给接收的 Isolate
,以确保只有一个 Isolate
可以访问该消息。
根据这些特性,所以我们在使用 Isolate
要注意这一点,当你在 Isolates
传递一个全局可变变量时,该全局变量会在其它 Isolate
复制一份,而在主隔离中却保持不变。
还有一点,目前 Web
平台还不支持 Isolate
。
本篇文章就到这里,感谢您的阅读,也希望您能关注我的公众号 Flutter技术实践,原创不易,您的关注是我更新下去最大的动力。