Dart 单线程模型的本质
众所周知 Dart 运行在单线程模型下,单线程模型在代码运行的过程中任意时刻只有一个线程参与(但整个周期内可能会有多个线程),意味着代码指令是顺序执行的也就不存在并发的情况。单线程模型的优点是实现简单、无资源竞争导致的异常,缺点是如果以 阻塞(Blocking)模式运行单线程模型的效率会非常低。为了提升单线程的运行效率 Dart 是以 非阻塞(Non-blocking)的模式运行在单线程模型中,因此 Dart 的单线程模型有着较高的效率,同时避免了资源竞争的问题。 阻塞(Blocking):当程序执行一个阻塞操作时,主线程会被挂起,直到该操作完成后才能继续执行后续的指令。在这期间,主线程无法执行其他的任务,因此程序会暂停执行。典型的阻塞操作包括文件I/O、网络I/O、等待用户输入等。在阻塞操作完成之前,主线程无法继续执行后续的指令。 非阻塞(Non-blocking):相比之下,当程序执行一个非阻塞操作时,主线程会立即返回,而不会被挂起等待操作完成。即使操作没有完成,主线程也可以继续执行后续的指令。 线程的阻塞、非阻塞通常与线程同步、异步对应。 阻塞:当程序执行一个阻塞任务时,当前线程会被挂起,只有在得到调用结果之后才会继续执行,这个过程称之为「同步调用」。 非阻塞:当程序执行一个阻塞任务时,当前线程不会停止执行,而是继续执行后面的其它任务,阻塞结束后再继续执行之前未完成的任务,这个过程称之为「异步调用」。 Dart 以非阻塞(Non-blocking)的单线程模型运行,自然也支持「同步」或「异步」调用。在 Dart 中一般用 Future 实例代表一个异步调用过程(也称为「Event Handler 宏任务」),每个 Future 异步任务具有相同的优先级且总是以先入先出(FIFO)的顺序执行。为了进一步提高响应实时性 Dart 提出了微任务(MicroTask)的概念,微任务优先级高于所有宏任务而微任务之间仍然以 FIFO 的顺序执行。假如某些宏任务需要满足一些前置条件,而微任务的存在保证了前置条件可以在宏任务执行前被设置,这进一步提高了Dart单线程模型的实时性与灵活性。 Dart 非阻塞的单线程模型由 事件循环(EventLoop) 来实现,它包含两个上面提到的两个队列: 宏任务队列(Event Queue) 与 微任务队列(MicroTask) ;EventLoop 优先消费微任务队列(main 函数结束后立即消费微任务),待微任务完全消费完之后再消费宏任务队列。每个宏任务消费完毕之后都会去检查微任务队列是否为空,不为空则优先消费微任务队列。下图来描述上面的过程。 实战 宏任务可以用 Future 对象创建,微任务则使用 scheduleMicrotask 全局函数来创建。可以通过一个例子来了解他们之前的优先级关系。 void main() async { print('m1'); var f = Future(() { print('f1'); scheduleMicrotask(() { print('fs1'); }); return Future....