async与await:
我们已经知道,actor中的public (shared)函数的返回值类型都必须为"a future",即以async修饰的其它类型,如async Nat。要访问async 值的结果,future的接受者要使用await表达式。可以总结为:
「await 作为广义上的左值,要接受一个async _ 作为右值」
遇到trap时程序回滚到何处?
A trap是一种不可恢复的运行时故障,例如,由零除、数组索引越界、数值溢出、循环耗尽或断言故障引起。
一种原子共享函数,其执行陷阱对封闭参与者或其环境的状态没有明显影响—任何状态更改都将被还原,它发送的任何消息都将被撤销。事实上,所有状态更改和消息发送在执行期间都是暂时的:它们只有在到达成功的提交点之后才提交。
在到达以下三个“提交点”之后,所有之前的状态更改和消息发送无法被撤回(回滚):
- 通过最终产生一个结果来隐式退出一个public (shared)函数时;
- 通过return或throw expressions来显式退出时;
- 遇到显式的await表达式时。
接下来举个例子来感受一下:
actor{
var s = 0;
var pinged = false;
public func show() : async (Nat, Bool) {
(s, pinged)
};
public func ping() : async () {
pinged := true;
};
// an atomic method
public func atomic() : async () {
s := 1; //被回滚
ignore ping(); //被回滚,因为没有await,还没有真正调用ping()
ignore 0/0; // trap!
};
// a non-atomic method
public func nonAtomic() : async () {
s := 1;
let f = ping();
s := 2;
await f;
s := 3; // this will not be rolled back!
await f; //会重新调用ping(),f的实质不是ping()的返回值,而是类似于函数的调用接口
ignore 0/0;// trap!
};
};
在test_1.mo的程序中,当我们调用atomic()函数后,我们会发现,s的值并没有改变为1,pinged的值也未被改为true。这是因为在遇到ignore 0/0;
这个trap时,会直接往回回滚,直到遇见“提交点”。而atomic()函数中并无这样的“提交点”,所以atomic()函数会被完全回滚。
而当我们调用nonAtomic()函数后,我们会发现,s变为3,pinged变为true。这是因为程序只能回滚到最后一个await f;
“提交点”。之前的状态更改均已提交,无法撤回。
再看一下代码,我们把atomic函数中的ignore ping();
改为await ping();
之后再来测试一下。
actor{
var s = 0;
var pinged = false;
public func show() : async (Nat, Bool) {
(s, pinged)
};
public func ping() : async () {
pinged := true;
};
// an atomic method
public func atomic() : async () {
s := 1; //不会被回滚
await ping(); //不会被回滚
ignore 0/0; // trap!
};
// a non-atomic method
public func nonAtomic() : async () {
s := 1;
let f = ping();
s := 2;
await f;
s := 3; // this will not be rolled back!
await f; //会重新调用ping(),f的实质不是ping()的返回值,而是类似于函数的调用接口
ignore 0/0;// trap!
};
};
我们发现,await ping();
之前的代码并没有被回滚,s和pinged的状态更改均已提交。这符合前面所说的规则。
深入理解:
我举这两个例子来对比是想再表达另外一点:
这里的ping()函数的返回值future可以认为还是这个函数,并不是函数调用的结果,如nonAtomic函数中的let f = ping();
,这里的f并不是ping函数中的运算结果,而是a future,还是代表这个函数,函数体并未运行,f的type为async (),而不是(),需要ignore来“忽略这个返回值”(如test_1.mo的atomic函数中所示那样),函数返回值并未真正参与到运算结果中。而这里的future(如f),可以放在await后面来组成一个await表达式,这个表达式的结果就是ping函数真正的运算结果,type为(),不需要ignore(如test_2.mo的atomic函数中所示那样)。
Comments 1 条评论
博客作者 Britt Jacka
Hi there! This post couldn’t be written any better! Reading through this post reminds me of my previous room mate! He always kept talking about this. I will forward this article to him. Pretty sure he will have a good read. Thank you for sharing!