资讯专栏INFORMATION COLUMN

【协程原理】 - cPython的VM真{{BANNED}}

Taonce / 672人阅读

摘要:以及和这是操作的。而且要特别注意的含义是把栈顶的值标识为,使得可以使用,所以还不是简单地把恢复就可以了这篇博客把的内部状态讲得非常清楚以上可以解释为什么没有人在里搞字节码的了,因为这个太{{BANNED}}。

kilim在JVM上实现了协程,其实现看起来挺容易的:http://www.malhar.net/sriram/kilim/thread_of_ones_own.pdf
在cPython上是否能够复制其技法呢?粗看上去,是很容易的,甚至比JVM更好实现:

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

frame的f_locals可以获得这个frame的所有局部变量的值(https://docs.python.org/3/library/inspect.html)

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

一个更加牛B的事情是,有人已经用@goto装饰器的方式在Python上实现了GOTO了
这个是Python 2版本的:http://code.activestate.com/recipes/576944-the-goto-decorator/
这个是Python 3版本的:https://github.com/cdjc/goto

这两个实现很好的展示了如何在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太{{BANNED}}。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37398.html

相关文章

  • 协程原理】 - 为什么greenlet状态无法被保存

    摘要:特别是最火的协程框架也无法保存状态,让人非常惋惜。但是因为栈的本身无法持久化,所以也就无法持久化。其难度在于,假设整个要持久化的调用栈全部都是内的,比如纯的。采取的是暴力地把整个栈区域拷贝到上的方式来保存其状态。 python主流的协程实现有五种: cPython的generator cPython的greenlet cPython的fibers stackless python ...

    verano 评论0 收藏0
  • 协程原理】 - Java中协程

    摘要:很长一段时间,我都很天真的认为,特别是以为代表的库,才是协程的乐土。里是没法实现协程,更别说实现这样可以的协程的。咱真的是太井底之蛙了。不完全列表如下还有一个据作者说是最的这些协程库的实现方式都是类似的,都是通过字节码生成达到的目的。 很长一段时间,我都很天真的认为python,特别是以gevent为代表的库,才是协程的乐土。Java里是没法实现协程,更别说实现stackless py...

    dongfangyiyu 评论0 收藏0
  • Swoole协程之旅-前篇

    摘要:协程完全有用户态程序控制,所以也被成为用户态的线程。目前支持协程的语言有很多,例如等。协程之旅前篇结束,下一篇文章我们将深入分析原生协程部分的实现。 写在最前   Swoole协程经历了几个里程碑,我们需要在前进的道路上不断总结与回顾自己的发展历程,正所谓温故而知新,本系列文章将分为协程之旅前、中、后三篇。 前篇主要介绍协程的概念和Swoole几个版本协程实现的主要方案技术; 中篇主...

    terasum 评论0 收藏0
  • 史上最优雅VM层取消Coroutine方式

    摘要:问题为了防止销毁时异步任务仍然在进行所导致的内存泄露,我们都会在方法中去取消异步任务。总结层可以天然自动监视销毁,我一直在找寻如何优雅的自动取消异步任务,在目前来看是最佳的方案。协程绝对是最先进的,效率最高,最优雅的技术栈组合。前提 在Android MVVM模式,我使用了Jetpack包中的ViewModel来实现业务层,当然你也可以使用DataBinding,关于Android业务层架构...

    cuieney 评论0 收藏0

发表评论

0条评论

Taonce

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<