20.Dart异步编程:Isolates和事件循环

前言

Dart 是单线程语言,它为 Futures Steams 后台作业,以及编写现代化、异步、响应式的 Flutter 应用程序所需的其他内容提供支持。

1

Isolate

Isolate 是所有 Dart 代码运行的地方。它就像机器中的一个小空间,它拥有自己的内存块和运行事件循环单一线程

在其他语言中,比如 C++ 你可以让多个线程共享相同的内存。并运行他们想要的代码。但是在 Dart 中,每个线程都有自己的 Isolate 和它自己的内存,它只处理事件。

许多 Dart 应用程序,在单一 Isolate 中运行所有代码。但是如果需要,你可以使用多个 Isolate。

2

如果你要运行的计算量太过庞大,如果它在主要的 Isolate 中运行的话,会导致应用程序扔掉当前的栈帧(Drop Frame)

子Isolate

你可以使用 Isolate.spawn 或者 Flutter 的计算函数,两者都会创建一个单独的 Isolate 来进行运算。让你主要的 Isolate 可以不受影响。

3

新的 Isolate 将会获得独立的事件循环和自己的内存,即使原本的 Isolate 是这个新 Isolate 的母体,原本的 Isolate 也不可以访问它。

4

这就是 Isolate 名称的来源。这些小空间之间彼此隔离。

Isolate 间通讯

Isolate 间合作的唯一方式,是来回传递消息。

一个 Isolate 会给另一个 Isolate 发送消息,接收消息的 Isolate 会使用他的事件循环处理消息。

5

Isolate 为什么这样设计

缺乏共享内存,可能听起来有些严格。 特别如果你是使用 Java C++ 这样的语言的话。但它对 Dart 编译器有一些关键性的好处。

比如:

  • Isolate 的内存分配和垃圾回收不需要

  • 因为他只有单一线程,因此如果它不忙,你就知道内存没有发生变化。这对 Flutter 应用程序非常有用。它有时需要快速构建和拆解很多 Widget。

事件循环

6

想象一下,应用程序的生命,在时间轴中延伸。期间会有很多外部信息的输入,而我们并不能预知这些信息什么时候会输入。这时我们就需要一个永不阻塞的线程来处理所有事件,它运行一个事件循环。

7

他从事件队列中,取出最旧的事件,处理它,返回,再取出下一个事件处理,依次循环,直到队列清空。

当事件清空,事件循环就会进入等待,直到有新的事件加入队列。

所有高级API都可用于异步编程。他们全部建立在这个简单的循环上。

Isolate 的使用

真多线程

通过日志我们发现:

sleep 的3秒并没有影响到 Isolate 调用,这里真正实现了多线程。

资源竞争

在进行 iOS 多线程开发的时候,我们会遇到资源竞争的问题。我们通常通过加锁来保证逻辑的正常。那么在使用 Isolate 的时候会不会也遇到这样的情况呢?

按照 iOS 开发经验理解,上面的输出应该是乱序的,而且 number 的读写也是会比较乱的。且 sleep 5秒后输出的 number 值会 +10。

我们看下输出:

  • 确实是乱序执行的,符合多线程的特征

  • number 值全部都只 +1 了,都是2

    • 这里就关系到前文有提到的 Isolate 的特性之一:

      • 含有独立的内存空间

      • 这里每个 Isolate 内的 number 都是独立的

线程间通讯

这里的通讯需要通过端口 Port 来进行,并且完成后需要手动释放。

输出:

compute

compute 是对 Isolate 的封装可以达到一样的效果:

输出:

进程间通讯

可以通过返回值的形式进行:

输出:

参考

https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a

https://www.youtube.com/watch?v=vl_AaCgudcY&t=53s

Last updated

Was this helpful?