Dart异步

《The Event Loop and Dart》译文

原文:https://webdev.dartlang.org/articles/performance/event-loop

Event loops and queues

event loop循环的从event queue中取出一个event并执行。

event-loop.png

event queue中的event可以是用户输入、文件IO、定时器等等:

event-loop-example.png

Dart’s single thread of execution

一旦一个dart function开始执行,就会继续执行下去直到它运行结束,换句话说,一条dart语句不能被其他的dart语句打断。

注意: A Dart command-line app 可以在不同的isolate上平行的执行代码。(Dart web app 不能直接创建额外的isolate,但可以创建worker) isolate相互隔离、不共享内存、通过传递消息来完成之间的通信。 除显示调用方法将dart语句放在isolate或者worker以外,dart语句全部运行在主线程。更多的信息可以参考 Use isolates or workers if necessary 。

Dart APP当在主isolate中调用完main()方法后,就按顺序循环执行event queue中的event,如下图:

Dart异步_第1张图片
event-loop-and-main.png

Dart’s event loop and queues

Dart APP存在一个单独的event loop和两个event queue(event queue 和 microtask queue)。

Microtask Queue存在的意义是在处理一个event时,部分语句稍后执行,但希望在下一个event之前处理完毕。
例如,当一个状态发生改变时,它将若干变化组合一起同步报告。microtask queue使得在DOM在显示状态变化前,状态可发生多次变化。

event queue包含了dart自定义event、系统event,但microtask queue只包含了自定义event,但我们期望Web实现包含浏览器microtask queue。

Dart异步_第2张图片
both-queues.png

注意:当event looper正在处理microtask queue中的Event时候,event queue中的event就停止了处理了,此时App不能绘制任何图形,不能处理任何鼠标点击,不能处理文件IO等等

Event-Looper优先执行Microtask Queue中的Event,直到Microtask Queue为空时,才会执行Event Queue中的Event

Dart中只能知道Event处理的先后顺序,但是并不知道某个Event执行的具体时间点,因为它的处理模型是一个单线程循环,而不是基于时钟调度(即它的执行只是按照Event处理完,就开始循环下一个Event,而与Java中的Thread调度不一样,没有时间调度的概念),也就是我们既是指定另一个Delay Time的Task,希望它在预期的时间后开始执行,它有可能不会在那个时间执行,需要看是否前面的Event是否已经Dequeue。

链式调用明确语句顺序

如果语句之间存在依赖关系,那就明确依赖关系。明确的依赖关系让别人能更容易理解。
下面是一种错误的用法:

// BAD because of no explicit dependency between setting and using
// the variable.
future.then(...set an important variable...);
Timer.run(() {...use the important variable...});

应该替换为:

// BETTER because the dependency is explicit.
future.then(...set an important variable...)
    .then((_) {...use the important variable...});

好的做法是用then()去明确变量设置和使用的前后顺序。(如果不管依赖是否正确执行,就要执行后续的语句,可以使用whenComplete()去代替when())
如果变量设置是异步操作,建议将变量使用语句放在new Future中。

// MAYBE EVEN BETTER: Explicit dependency plus delayed execution.
future.then(...set an important variable...)
    .then((_) {new Future(() {...use the important variable...})});

How to schedule a task

当有代码需要在后续任务执行的时候,可以通过dart:async提供的两种方法实现:

1.使用Future类,可以将任务加入到Event Queue的队尾
2.使用scheduleMicrotask函数,将任务加入到Microtask Queue队尾

Use the appropriate queue (usually: the event queue)

尽可能使用event queue,microtask queue会阻塞event queue的执行。
如果语句需要在event queue中其他event之前执行,可以通过scheduleMicrotask()添加到microtask queue。

Dart异步_第3张图片
scheduling-tasks.png

Event queue: new Future()

可以通过new Future() 或者 new Future.delayed()来使用event queue。

注意:也可以使用Timer来调用event queue, 但是如果存在未截获的exception,app会退出。

立即加入event queue,使用new Future():

// Adds a task to the event queue.
new Future(() {
    // ...code goes here...
});

等待一段时间后,再加入event queue,使用use new Future.delayed():

// After a one-second delay, adds a task to the event queue.
new Future.delayed(const Duration(seconds:1), () {
// ...code goes here...
});

当需要做动画的时候,不要使用Future,而需要使用animateFrame

PS:
1.FutureTask执行完成后,then()会立即执行(then并没有创建新的event丢到event 1ueue中,而只是Function Call);
2.当FutureTask在then()被调用之前执行完成,则会创建一个task,并将该task的添加到microtask queue中;
3.Future只是创建了一个event,将event插入到了event queue的队尾;
4.Future.value()跟第二条一样,创建Task丢到microtask Queue中;
5.Future.sync()立即执行传入的function,如果function返回future,则会创建Task丢到microtask Queue中执行。

Microtask queue: scheduleMicrotask()

使用scheduleMicrotask
在dart:async库中定义了scheduleMicrotask()方法来使用microtask queue。

scheduleMicrotask(() {
    // ...code goes here...
});

另外一种使用microtask queue的方式,是在Future中调用then()。

Use isolates or workers if necessary

当有计算很繁重的任务时,则需要使用isolate或者Worker来执行,以保持App对用户操作的及时响应。Isolate可能是一个单独的线程,或者一个单独的进程,这取决于Dart的具体实现。通常情况下可以根据你的cpu的个数来决定isolate的数量。但你也可以使用超过cpu个数的isolate,前提是你有好的app架构,让不同的isolate来分担不同的代码块运行,并能保证这些isolate之间没有数据共享。

你可能感兴趣的:(Dart异步)