canonical 写了一篇关于continuation的简短精悍的文章,读后收益非浅。
http://www.blogjava.net/canonical/archive/2005/12/12/23406.html
有一次和徐昊(id比较难记,大致形态是...ramindox...)讨论seaside (a smalltalk web framework),讨论seaside对continuation的支持。
我的观点是,continuation的问题之一,在于潜在的性能问题。比session里面放置数据,还要影响性能。
这次终于看到canonical的言论,贴在这里作为理论依据。
canonical 写道
最近struts和webwork步cocoon和rife的后尘, 相继引入了对web continuation的支持, 在后台程序中实现了对于page flow的完整描述, 这无疑是一些非常有趣的工作. 例如现在我们可以编写
void onRequest(){
funcA();
Input input = sendPageAndWait("collectionInfoFromUser.jsp");
handleInput(input);
}
在调用sendPageAndWait的时候, web框架会保存当前函数调用的continuation, 向用户返回页面collectionInfoFromUser.jsp, 等待用户提交表单之后, web框架重新激活我们所保存的continuation, 继续执行我们的函数. 这种做法与系统调用和线程调度等机制是非常类似的.
有些人认为这种基于continuation的方式可以自然的解决在session中保存并清理变量的问题, 这显然是一种大材小用的做法, 而且事实上使用一种通用的continuation 实现很有可能在无意中保存了过多的临时变量, 从而对系统性能造成极大的损害.
另外,后面的这部分令我更加感兴趣。
canonical 写道
有趣的是, 在Mach3.0中对系统线程所作的一项改进即称为continuation, 其动因恰在于避免保留线程堆栈,希望使用完全无状态的continuation函数.(参见Uresh Vahalia的经典著作"UNIX Internals" http://www.china-pub.com/computers/common/info.asp?id=12731).
在传统的系统调用实现中
syscall_l(argl)
{
...
thread_block();
f2(arg);
return;
}
f2(arg){
...
return;
}
thread_block()函数会阻塞住当前系统调用过程, 并自动保存所有堆栈变量, 等待内核重新把控制权返回给调用函数. 在使用continuation函数的方式中, 我们需要显式的存取状态变量,
syscall_1(arg1)
{
...
save arg1 and any other state information;
thread_block(f2); // thread_block(void * (contiuationFunc));
/* not reached */
}
f2()
{
restore argl and any other state information;
...
thread_syscall_return(status);
}
在这种方式中thread_block()并不返回到调用者。线程恢复执行时,内核把控制权传递给f2(). 函数thread_syscall_return()用来从系统调用返回到用户级。"整个过程对用户是透明的,用户所看到的只是从系统调用一个同步返回 ". 在Linux系统内核中所使用的bottom_half机制也是基于类似的原理.
这段讲的大概是系统内核级别对continuation实现的优化。
但似乎在使用上,就不那么透明了,必须显示使用。
"在使用continuation函数的方式中, 我们需要显式的存取状态变量,"
徐昊也提到smalltalk vm对continuation做的一些优化。比如,context (runtime stack)过期清除回收,等。