Python虚拟机初始化
文章目录
阅读条件:
C语言基础, Python虚拟机基本了解
前言
Python源码剖析一书的第二部分主要讲述了虚拟机主循环是如何运行的.那么在命令行启动python之后,到执行主循环之前都经历了哪些事情呢?这是我们今天要解决的问题.
另外还要一个思考: 在写python代码的时候,我们经常会写:
|
|
这个balabala
是如何能运行呢?
入口
在python-2.5.6中,代码入口位于:
|
|
我们要剖析的初始化动作主要在Py_Initialize
,而初始化完成后,进入运行时就需要依靠PyRun_AnyFileExFlags
.
初始化
Py_Initialize
这个函数我们看到啥也没干,直接进入Py_InitializeEx
Py_InitializeEx
这个函数就厉害了,我们慢慢看.
创建进程结构体
|
|
在python中,使用PyInterpreterState
结构体来描述进程.本质上,后面的初始化工作就是在填充这个进程描述结构体.
|
|
创建线程结构体
|
|
同进程类似,Python使用PyThreadState
来描述线程.
|
|
可以想象,线程结构体必然要挂到进程体之下.同样的在线程结构体中,我们发现了_frame
的身影.说明Frameobject又挂在了线程之下.
初始化内置数据结构
|
|
这部分内容可以衔接到,我们之前谈到过的内置对象初始的过程中.
设置__builtin__ module
|
|
正是这里,我们创建了__builtin__
module,并将我们耳熟能详的大量内置方法放了进去.
设置sys module
|
|
可以看到sys module的方法,在初始化的时候,都可以添加完毕.只是我们在自己的名字空间还是看不到他们.
设置搜索路径
|
|
设置__main__ module
|
|
这里我们稍微说下这个__main__
,这个在初始化完成后,基本上是个空壳.但是我们后面我们执行过程都在这个名字空间中,这也是我们上面问题的答案.
至此,我们的初始化工作大体完成.
运行
PyRun_AnyFIleExFlags
兵分两路,一个是交互式执行,一个是脚本执行.
|
|
交互执行
PyRun_InteractiveOneFlags
本质上,这里就是编译输入的语句.然后交由run_mod
执行
脚本执行
PyRun_SimpleFileExFlags
首先,判断是执行pyc
文件,还是编译执行py
文件.然后调用PyRun_FileExFlags
,这个函数也会调用run_mod
.
这里我们看到其实执行的真正入口就是run_mod
.交互执行和脚本执行殊途同归.
run_mod
PyAst_Compile
根据AST语法树,编译生成python字节码.也就是PyCodeObject.
PyEval_EvalCode
这个函数会调用PyEval_EvalCodeEx
.千辛万苦,我们终于走到了我们熟悉的虚拟机主循环.
总结
这里,我们总结下python虚拟机的初始化过程.
首先是准备进程,线程相关结构体.然后初始化一些必备模块,如builtin
, sys
, __main__
.
第二步是编译输入的文件,从而生成PyCodeObject.再之后就是调用执行主逻辑PyEval_EvalCodeEx
来运行这个PyCodeObject.
从此之后,python虚拟机就完全运行起来啦.
文章作者 成祎
上次更新 2018-01-19