Kilim是一个Java的actor框架,让你可以在JVM里使用基于协程的actor模型,bluedavy曾经介绍过,这里不再赘言。这篇blog的目的在于分析下kilim实现的基本原理,看看怎么在JVM上实现协程。

在一些语言层面上支持协程的语言,如lua、ruby,都是直接在VM级别支持协程,VM帮你做context的保存和恢复。JVM没有提供这样的指令来保存和恢复方法栈的状态,因此kilim的实现还是需要在bytecode级别做文章。首先,试想下,如果是你来实现协程,你会怎么做?协程的两个基本原语resume和yield,resume运行协程,yield让出执行权,下次resume的时候会从yield的地方重新执行,并且context保持不变。可见,你需要做这么几个事情:
1、在yield的时候保存当前context。
2、在resume的时候恢复context,并根据pc计数来决定从哪里恢复执行。
3、半协程的实现来说,还需要一个调度器来调度所有协程。
4、为了做到用户代码透明,可能需要某种手段去修改用户代码,自动帮你做上面三个事情。

kilim的实现就是干了这么几个事情:
1、利用字节码增强,将普通的java代码转换为支持协程的代码。
2、在调用pausable方法的时候,如果pause了就保存当前方法栈的State,停止执行当前协程,将控制权交给调度器
3、调度器负责调度就绪的协程
4、协程resume的时候,自动恢复State,根据协程的pc计数跳转到上次执行的位置,继续执行。

下面是来自kilim文档的一个例子,同一段代码,在字节码增前前后的变化:

左边是原始代码,右边是通过字节码增强后的代码。其中h方法是pausable的,也就是说可能被暂停阻塞的,g方法因为调用了h这个方法也变成了pausable。

首先看,原始的h方法是没有传入任何参数的,增强后的代码,多了个参数Fiber,指向当前的协程,同样,g方法本来只有一个参数n,现在在后面也多了个Fiber类型的参数,同样是指向当前执行的协程。

其次,在原始的g方法里,一旦调用,马上进入一个for循环。但是在增强后的代码,多了个switch派发的过程,这就是前面提到的,根据当前的Fiber的pc计数,跳转到上一次执行的地方执行。如果是第一次resume,也就是启动协程,那么就将初始循环的i设置为0,进入原始代码的循环部分。Fiber有一个pc计数,称为程序计数器,用于指向恢复context的时候需要跳转到位置。

第三,在g方法里调用h这个可被暂停阻塞的方法的时候,在h方法前后多了一些调用:

[java]
f.down();
h(f);
f.up();
[/java]

kilim的Fiber将每个pauseable方法的调用组织成一个栈,每个pauseable方法都有一个activationframe,翻译过来可以称为活动栈帧,这个栈帧记录了当前的栈的State,注意这个栈跟java本身的方法调用栈区分开来,一个是VM层面的,一个是kilim框架层面的。这里的down方法就是将栈向下延伸,表示将调用一个pauseable方法,并且设置当前State和pc计数。
调用了down之后,才是调用实际的h方法,最后还要调用一次up,顾名思义,就是说一次pauseable方法调用完成,fiber的活动栈要递增一层,回到上一层。但是h方法调用可能出现四种情况:
1、正常的顺利返回,没有状态需要恢复,所谓NOT_PAUSING__NO_STATE
2、也是正常返回,有状态需要恢复,也就是NOT_PAUSING__HAS_STATE
3、h方法暂停阻塞,当前没有保存状态,需要保存状态,这是第一次暂停的时候,称为PAUSING__NO_STATE
4、h方法暂停阻塞,当前已经有状态,不需要保存状态,这是第一次暂停之后的resume再次暂停,称为PAUSING__HAS_STATE,通常不需要处理什么。

第四,可以看到,在up之后,就要根据up返回的上述4种状态执行不同的逻辑:

[java]
if (f.isPausing){
//第一次暂停,没有状态
if (!f.hasState){
//new一个State_I2,并保存i和n
f.state = new State_I2(i,n);
//记录pc,还记的前面的switch吗?
f.pc = H1;
}
return;
} else if (f.hasState)
//正常返回,有状态需要恢复,恢复i和n
State_I2 st = (State_I2) f.state;
i = st.i1; n = st.i2;
}
[/java]

这里没有处理NOT_PAUSING__NO_STATE和PAUSING__HAS_STATE,因为这两种情况在这里不需要处理。

通过上面的分析,我想大家对kilim的实现应该已经有一个很基本的认识。下一步,我们分析一个实际的代码例子,查看整个运作流程。

转载于:https://blog.51cto.com/aliapp/1325746

Kilim实现浅析(一)相关推荐

  1. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  2. 浅析Python中bytes和str区别

    本博转载自:Chown-Jane-Y的浅析Python3中的bytes和str类型 Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示, ...

  3. 学习《Linux设备模型浅析之设备篇》笔记(深挖一)

    这篇文章既然说了是浅析,那就是跳过了一些东西,我们把这些跳过的东西给它尽可能的补回来 今天登陆 lxr.free-electrons.com 发现内核版本已经升级到3.15了,那以后都使用3.15的源 ...

  4. 学习《Linux设备模型浅析之设备篇》笔记(一)

    最近在学习Linux设备模型,前面几篇文章也是读这篇的时候遇到问题,然后为了搞清楚先转去摸索才写出来的. 当然了,刚开始是先读到<Linux那些事儿之我是Sysfs>,搞不清楚才去读的&l ...

  5. 架构周报| 浅析MySQL JDBC连接配置上的两个误区

    经典案例 \\ 浅析MySQL JDBC连接配置上的两个误区:相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很 ...

  6. 超级账本(Hyperledger Fabric)之权限管理浅析

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 超级账本(Hyperledger Fabric)之权限管理浅析 超级账本是联盟链的代表,而其相对于共链(例如比特币,以太 ...

  7. linux内核SMP负载均衡浅析

    需求       在<linux进程调度浅析>一文中提到,在SMP(对称多处理器)环境下,每个CPU对应一个run_queue(可执行队列).如果一个进程处于TASK_RUNNING状态( ...

  8. CAS、原子操作类的应用与浅析及Java8对其的优化

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:CoderBear juejin.im/post/5c7a8 ...

  9. Python标准库queue模块原理浅析

    Python标准库queue模块原理浅析 本文环境python3.5.2 queue模块的实现思路 作为一个线程安全的队列模块,该模块提供了线程安全的一个队列,该队列底层的实现基于Python线程th ...

最新文章

  1. python 添加进度条
  2. [ATF]-ATF启动--BL31跳转到optee和uboot
  3. 通过服务器给多台计算机装系统,怎么快速给机房多台电脑安装系统?
  4. win2008 mysql_mysql5.7.17在win2008R2的64位系统安装与配置实例
  5. Wijmo 更优美的jQuery UI部件集:复合图表(CompositeChart)
  6. 3.2 读入两个参数
  7. 开启防火墙并添加出入站规则
  8. 三星开出的57619美元年薪 却还是留不住千禧一代
  9. 小米小爱蓝牙音箱_至今为止功能最全面的「小爱同学」!小米小爱音箱Pro体验...
  10. Java 程序员必会的「垃圾回收」算法
  11. 什么样的团队才是理想中的团队? (转自AtTeam官微的博客)
  12. 2020寒假第三周总结
  13. PS颜色模式及修图工具
  14. emule服务器地址列表地址
  15. ElasticSearch 学习(二)—— IK 分词器和 Kibana
  16. ibm服务器卡在开机界面_使用HTTPS配置IBM Integration Bus Web用户界面
  17. Wps文档如何转换为pdf文件
  18. 【数论】GDKOI day1 讲座(数论基本知识 详)
  19. Fluent求解器——亚松弛因子
  20. 六级高频词汇——Group06

热门文章

  1. 登录不上_无法登录远程:出现身份验证错误,要求的函数不受支持
  2. python作品_Python爬取图虫网摄影作品
  3. java swing 禁用鼠标事件_Java学习笔记:swing中树控件,设置树节点的图标,按钮美化,鼠标事件,禁止鼠标双击...
  4. 以array开头的php函数,PHP 常用数组函数详解
  5. python可变类型和不可变类型_Python-5 可变类型与不可变类型
  6. 零窗口探测怎么抓包_超低暗电流高性能近红外硅基光电探测器研究获进展
  7. /usr/lib/python2.6/site-packages/pycurl.so: undefined symbol: CRYPTO_set_locking_callback
  8. 用pandas填充时间序列缺失值
  9. 平衡二叉树 构造方法
  10. Scala之部分应用函数