Python概述

综述

  • 语言的具体实现可能发生改变、其他实现可能使用不同方式
  • 在语言的参考文档中加入过多细节实现很危险

Python实现

python只是一种语言,其具体解释器实现有很多种

  • CPython:C语言实现,最原始版本

    • 通常就被称为Python,其他实现区分时才强调为CPython
    • 新语言特性通常较早出现
  • Jython:Java实现

    • 将Python代码编译为Java字节码
    • 可以左线Java应用的脚本语言、创建需要Java类库支持的 应用
    • 在JVM上运行
  • Python for .NET:实际上使用CPython实现,但是属于.NET 托管应用,可以引入.NET类库

  • IronPython:.NET实现

    • 生成IL的完全Python实现,将Python代码直接编译为.NET 程序集
  • PyPy:RPython(Python语言子集)实现

    • JIT编译器,执行效率高于CPython
    • 非栈式支持
    • 允许方便修改解释器,鼓励对语言本身进行实验
  • CPython是解释器实现版本,cython是将Python代码翻译为 C插件的项目/包

Notation说明

标注:词法、句法解析的描述使用修改过的BNF语法标注

1
2
name ::= lc_letter(lc_letter | "_")*
lc_letter ::= "a"..."z"
  • ::=:声明规则,左侧为规则名称
  • |:分隔可选项
  • *:前一项的零次、多次重复
  • +:前一项的一次、多次重复
  • []:括起内容可选,即出现零次、一次
  • ():分组
  • "":固定字符串包含在引号内
  • :空格仅用于分隔token
  • ...:三个点分割的本义字符表示在指定区间范围内的任意 单个字符
  • <>:对所定义符号的非常描述,在必要时用于说明“控制字符” 意图
  • 每条规则通常为一行,多个可选项规则可用|为界分为多行
  • 词法定义:作用域输入源中的单独字符
  • 句法定义:作用于词法分析生成的token stream

约定

  • 实例方法:定义在类命名空间中、未因访问而绑定函数
  • 绑定方法:已绑定实例方法
  • 静态方法
  • 类方法
  • [类]实例:类实例化所得对象
  • 对象:泛指所有python对象,包括类、实例

Global Intepretor Lock

全局内存锁:GIL,任何python字节码执行前必须获得的解释器锁

  • 在任何时刻,只能有一个线程处于工作状态
  • 避免多个线程同时操作变量导致内存泄漏、错误释放

优势

  • GIL实现简单,只需要管理一把解释器锁就能保证线程内存安全

    • 当然GIL只能保证引用计数正确,避免由此导致内存问题
    • 还需要原子操作、对象锁避免并发更新问题
  • GIL单线程情况下性能更好、稳定,若通过给所有对象引用计数 加锁来实现线程安全

    • 容易出现死锁
    • 性能下降很多
  • 方便兼容C遗留库,这也是python得以发展的原因

    • 很多python需要的C库扩展要求线程安全的内存管理

影响

  • Python线程是真正的操作系统线程

    • 在准备好之后必须获得一把共享锁才能运行
    • 每个线程都会在执行一定机器指令和后切换到无锁状态, 暂停运行
    • 事实上程序在开始时已经在运行“主线程”
    • 解释器检查线程切换频率sys.getcheckinterval()
  • Python线程无法在多核CPU间分配,对CPU-Bound程序基本没有 提升效果,对于IO-Bound的程序性能仍然有巨大帮助

解决方案

  • 多进程

    • 进程分支:os.fork
    • 派生进程:multiprocessing.Processconcurrent.futures
  • C语言库封装线程:ctypescython

    • C扩展形式实现任务线程可在python虚拟机作用域外运行 可以并行运行任意数量线程
    • 在运行时释放GIL、结束后继续运行python代码时重新获取 GIL,真正实现独立运行
  • 使用其他版本Python解释器:只有原始Python版本CPython使用 GIL实现

    • Jython
    • IronPython
    • PyPy

Python最高层级组件

完整的Python程序

  • 完整的python程序会在最小初始化环境中被执行

    • 所有内置、标准模块均可用,但均处于未初始化状态
    • 只有sysbuiltins__main__已经初始化
    • __main__模块为完整程序的执行提供局部、全局命名空间
  • 完整程序可通过三种形式传递给解释器

    • -c命令行选项传递字符串
    • 文件作为第一个命令行参数
    • 标准输入
    • 若文件、标准输入是tty设备,解释器进入交互模式,否则 将文件当作完整程序执行
  • 解释器也可以通过交互模式被发起调用

    • 每次读取执行一条语句,语句会在__main__命名空间中 被执行
    • 初始环境同完整程序

输入类型

文件输入

文件输入:从非交互式文件读取的输入,具有相同形式

1
file_input ::= (NEWLINE|statement)*
  • 适合以下几种情况

    • 解析完整的python程序(从文件、字符串)
    • 解析模块
    • 解析传递给exec()函数的字符串

交互式输入

交互式输入:从tty设备读取输入

1
interactive_input ::= [stmt_list] NEWLINE | compound_stmt NEWLINE
  • 注意
    • 交互模式中(最高层级)复合语句后必须带有空行,帮助 解释器确定输入的结束

表达式输入

表达式输入

1
eval_input ::= expression_list NEWLINE*
  • eval被用于表达式输入
  • 忽略开头空白
Author

UBeaRLy

Posted on

2019-06-09

Updated on

2019-06-09

Licensed under

Comments