cpython_【协程原理】 - cPython的VM真变态

kilim在JVM上实现了协程,其实现看起来挺容易的:http://www.malhar.net/sriram/kilim/thread_of_ones_own.pdf

在cPython上是否能够复制其技法呢?粗看上去,是很容易的,甚至比JVM更好实现:

利用sys._getframe(0)可以获得call stack上的任意frame

虽然python不支持goto或者longjmp,然后cPython的bytecode是支持JUMP_ABSOLUTE的(https://docs.python.org/3/library/dis.html)

这两个实现很好的展示了如何在Python中做类似JVM上ASM库做的事情,字节码增强。

===============

但是,cPython的VM对于frame状态的建模使得在cPython上实现kilim,比JVM要难得多。在cPython某个指令执行的那一刻,有五个部分的状态

builtins

globals

locals

value_stack

block_stack

前三个都是python里做动态执行的常客,没啥困难的。而且frame通过inpsect可以很轻易的获得locals的值。而后两者是非常困难的,我们可以来看一段我随便写的代码

for i in range(1):

print(i)

生成的bytecode是

0 SETUP_LOOP 30 (to 33)

3 LOAD_GLOBAL 0 (0)

6 LOAD_CONST 1 (1)

9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

12 GET_ITER

>> 13 FOR_ITER 16 (to 32)

16 STORE_FAST 0 (0)

19 LOAD_GLOBAL 1 (1)

22 LOAD_FAST 0 (0)

25 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

28 POP_TOP

29 JUMP_ABSOLUTE 13

>> 32 POP_BLOCK

>> 33 LOAD_CONST 0 (0)

36 RETURN_VALUE

我们可以看到一个简单的循环,产生了一对SETUP_LOOP和POP_BLOCK,这个是操作block_stack的。以及GET_ITER和FOR_ITER这是操作value_stack的。如果我们想要直接跳入到print(i)这一行,那么就要恢复当时的block_stack,以及当时的value_stack。而且要特别注意GET_ITER的含义是把栈顶的值标识为ITER,使得FOR_ITER可以使用,所以还不是简单地把value_stack恢复就可以了

GET_ITER

Implements TOS = iter(TOS).

这篇博客把python的frame内部状态讲得非常清楚:http://tech.blog.aknin.name/tag/block-stack/

以上可以解释为什么没有人在python里搞字节码的trick了,因为这个VM太变态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值