close
当前位置: 物联网在线 > 技术文库 > ios >

Dart异步任务与消息循环机制

Dart与消息循环机制

异步任务在Dart中随处可见,例如许多库的方法调用都会返回Future对象来实现异步处理,我们也可以注册Handler来响应一些事件,如:鼠标点击事件,I/O流结束和定时器到期。

这篇文章主要介绍了Dart中与异步任务相关的消息循环机制,阅读完这篇文章后相信你可写出更赞的异步执行代码。你也能学习到如何调度Future任务并且预测他们的执行顺序。

在阅读这篇文章之前,你最好先要了解一下基本的 Future用法 。

基本概念

如果你写过一些关于UI的代码,你就应该熟悉消息循环和消息队列。有了他们才能保重UI的绘制操作和一些UI事件,如鼠标点击事件可以被一个一个的执行从而保证UI和UI事件的统一性。

<!-- more -->

消息循环和消息队列

一个消息循环的职责就是不断从消息队列中取出消息并处理他们直到消息队列为空。

消息队列中的消息可能来自用户输入,文件I/O消息,定时器等。例如下图的消息队列就包含了定时器消息和用户输入消息。

上述的这些概念你可能已经驾轻就熟了,那接下来我们就讨论一下这些概念在Dart中是怎么表现的?

Dart的单线程执行

当一个Dart的方法开始执行时,他会一直执行直至达到这个方法的退出点。换句话说Dart的方法是不会被其他Dart代码打断的。

Note:一个Dart的命令行应用可以通过创建isolates来达到并行运行的目的。isolates之间不会共享内存,它们就像几个运行在不同进程中的app,中能通过传递message来进行交流。出了明确指出运行在额外的isolates或者workers中的代码外,所有的应用代码都是运行在应用的main isolate中。要了解更多相关内容,可以查看

正如下图所示,当一个Dart应用开始的标志是它的main isolate执行了main方法。当main方法退出后,main isolate的线程就会去逐一处理消息队列中的消息。

Dart异步任务与消息循环机制

事实上,上图是经过简化的流程。

Dart的消息循环和消息队列

一个Dart应用有一个消息循环和两个消息队列-- event队列 和 microtask队列 。

event队列包含所有外来的事件:I/O,mouse events,drawing events,timers,isolate之间的message等。

microtask 队列在Dart中是必要的,因为有时候事件处理想要在稍后完成一些任务但又希望是在执行下一个事件消息之前。

event队列包含Dart和来自系统其它位置的事件。但microtask队列只包含来自当前isolate的内部代码。

正如下面的流程图,当main方法退出后,event循环就开始它的工作。首先它会以FIFO的顺序执行micro task,当所有micro task执行完后它会从event 队列中取事件并执行。如此反复,直到两个队列都为空。

Dart异步任务与消息循环机制

注意:当事件循环正在处理micro task的时候。event队列会被堵塞。这时候app就无法进行UI绘制,响应鼠标事件和I/O等事件

虽然你可以预测任务执行的顺序,但你无法准确的预测到事件循环何时会处理你期望的任务。例如当你创建一个延时1s的任务,但在排在你之前的任务结束前事件循环是不会处理这个延时任务的,也就是或任务执行可能是大于1s的。

通过链接的方式指定任务顺序

如果你的代码之间存在依赖,那么尽量让他们之间的依赖关系明确一点。明确的依赖关系可以很好的帮助其他开发者理解你的代码,并且可以让你的代码更稳定也更容易重构。

先来看看下面这段错误代码:

// 这样写错误的原因就是没有明确体现出设置变量和使用变量之间的依赖关系 future.then(...set an important variable...); Timer.run(() {...use the important variable...});

正确的写法应该是:

// 明确表现出了后者依赖前者设置的变量值 future.then(...set an important variable...) .then((_) {...use the important variable...});

为了表示明确的前后依赖关系,我们可以使用 then()() 来表明要使用变量就必须要等设置完这个变量。这里可以使用 whenComplete() 来代替then,它与then的不同点在于哪怕设置变量出现了异常也会被调用到。这个有点像java中的finally。

如果上面这个使用变量也要花费一段时间,那么可以考虑将其放入一个新的Future中:

future.then(...set an important variable...) .then((_) {new Future(() {...use the important variable...})});

使用一个新的Future可以给事件循环一个机会先去处理列队中的其他事件。

怎么安排一个任务
(责任编辑:ioter)

用户喜欢...

美国海军为水下机器人设计充电站 延长任务时间

随着自动科技的进展,各类型的无人机愈来愈普及,美国海军也全力研发,这些无人机器人的任务多半必须长期进行...


机器人总动员正在上演

2017世界机器人大会如约而至,北京地铁亦庄线荣昌东街站也迎来了客流高峰。就在这里,北京亦创国际会展中心集学...


交流异步电动机调速方法

电机调速节能一直被广泛关注。风机和泵类采用电动机调速装置来代替阀门和挡板调节流量,有明显节电效果。...


基于TI-RTOS的CC2650DK开发(8)---任务

3.6 Tasks SYS/BIOS task对象是由Task模块管理的线程。Tasks的优先级高于Idle Loop并低于硬件中断和软件中断。参阅video introducing Tasks进行概览。 Task模块基于task的优先级和当前task的运行状态动态地安...


三相异步电动机种类繁多,该如何选择合适的呢?

三相异步电动机的型号很多,但是我们如何选择合适的三相异步电动机呢?有哪些选择依据呢?大兰电机告诉您在选...


Unity+NGUI打造网络图片异步加载与本地缓存工具类(一)

我们在移动端的开发中,异步网络图片加载用的非常的多,在unity当中虽然有AssetBundle的存在,一般是先加载好游戏资源然后再进入场景,但是还有不少地方能够用到异步网络图片的加载以及...


Unity+NGUI打造网络图片异步加载与本地缓存工具类(二)

接上文,我们的工具类中的主要方法: public void SetAsyncImage(string url,UITexture texture) 按照前文分析的图片加载步骤来 public void SetAsyncImage(string url,UITexture texture){ //开始下载图片前,将UITexture的主...


绕线式异步电动机的起动

selina 在 周五, 06/02/2017 - 11:09 提交 绕线式异步电动机的起动 绕线式三相异步电动机可以在转子回路中串入电阻进行起动,这样就减小了起动电流。一般采用起动变阻器起动,起动时全部电阻...


如何解决变频器对电机的影响

不论那种形式的变频器,在运行中均产生不同程度的谐波电压和电流,使电动机在非正弦电压、电流下运行。拒资料...


监管新思路:提供精准定位的“北斗一张网”或无意承担了监管任务

自民航局适航司发布从6月1日重量超过250克的无人机须实名注册开始,这段时间有关无人机监管的分析多了起来,监管...