首页 > 技术文章 > Python 和 Java的对比

shawshawwan 2018-12-20 20:10 原文

(今天实习面试又问道这个问题了,答的不是很好= = )

静态语言和动态语言

常见的语言按照动态语言和静态语言来分类:

  • 静态语言:
    java, c, c++, go等
    强类型语言(静态类型语言)是指需要进行变量/对象类型声明的语言,一般情况下需要编译执行。强类型语言是一旦变量的类型被确定,就不能转化的语言。

  • 动态语言:
    python, javascript, php, ruby等
    弱类型语言(动态类型语言)是指不需要进行变量/对象类型声明的语言,一般情况下不需要编译(但也有编译型的)。动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
    弱类型语言则反之,一个变量的类型是由其应用上下文确定的。

  • 静态语言优势

由于类型的强制声明,使得IDE有很强的代码感知能力,故,在实现复杂的业务逻辑、开发大型商业系统、以及那些生命周期很长的应用中,依托IDE对系统的开发很有保障;
由于静态语言相对比较封闭,使得第三方开发包对代码的侵害性可以降到最低;

  • 动态语言的优势:
  1. 在静态语言中的一些高级概念,如java中的反射以及基于反射实现的AOP, 这些概念对java初学者以及只有一两年工作经验的人来说,这几个概念是很难理解的,更不用说如何去自己实现。如果大家使用过AOP的话就会明白这几个概念从理解到熟练使用是比较难的, 而且开发效率会比较低,尽管同学可能会说“其实使用起来还是很简单啊”, 那可能是因为你没有用过动态语言中的装饰器。
  2. 动态语言中对于java中的AOP这种概念直接使用装饰器就可以完成而且是python语言本身的一部分。并不像java中还需要引入第三方来完成。
  3. python能轻松完成这些正是由于python是一门动态语言, 动态语言的特性使得大家去自己控制整个类的初始化以及动态去改变对象变的异常简单, 这些特性使得动态语言的灵活性远远超过静态语言。

解释型语言和编译型语言

这里的解释执行是相对于编译执行而言的。我们都知道,使用C/C++之类的编译性语言编写的程序,是需要从源文件转换成计算机使用的机器语言,经过链接器链接之后形成了二进制的可执行文件。运行该程序的时候,就可以把二进制程序从硬盘载入到内存中并运行。

  • python的执行过程和Java是类似的:
    python解释器将源代码转换为字节码,然后再由python解释器来执行这些字节码。

一个具体的Python程序的执行过程:

 - 执行python程序后,将会启动 Python 的解释器,然后将python程序编译成一个字节码对象 PyCodeObject。
 - 在运行期间,编译结果也就是 PyCodeObject 对象,只会存在于内存中,而当这个模块的 Python 代码执行完后,就会将编译结果保存到了 pyc 文件中,这样下次就不用编译,直接加载到内存中。pyc 文件只是 PyCodeObject 对象在硬盘上的表现形式。
 - 这个 PyCodeObject 对象包含了 Python 源代码中的字符串,常量值,以及通过语法解析后编译生成的字节码指令。PyCodeObject 对象还会存储这些字节码指令与原始代码行号的对应关系,这样当出现异常时,就能指明位于哪一行的代码。
  • Java也是先编译成字节码,再去执行
    解释器,java很特殊,java是需要编译的,但是没有直接编译成机器语言,而是编译成字节码,然后在Java虚拟机上用解释的方式执行字节码。Python也使用了类似的方式,先将python编译成python字节码,然后由一个专门的python字节码解释器负责解释执行字节码。

Python 的GIL

GIL的全称是Global Interpreter Lock(全局解释器锁)来源是python设计之初的考虑,为了数据安全所做的决定。

在Python多线程下,每个线程的执行方式:
1.获取GIL
2.执行代码直到sleep或者是python虚拟机将其挂起。
3.释放GIL

可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。
而每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行),这就是为什么在多核CPU上,python的多线程效率并不高。
每个进程有各自独立的GIL,互不干扰,这样就可以真正意义上的并行执行,所以在python中,多进程的执行效率优于多线程(仅仅针对多核CPU而言)。

由于 GIL 的存在,Python 的多线程性能十分低下,无法发挥多核 CPU 的优势,性能甚至不如单线程。因此如果你想用到多核 CPU,一个建议是使用多进程或者协程

Python垃圾回收

在讲到垃圾回收的时候,通常会使用引用计数的模型,这是一种最直观,最简单的垃圾收集技术。Python 同样也使用了引用计数,但是引用计数存在这些缺点:

  1. 频繁更新引用计数会降低运行效率
  2. 引用计数无法解决循环引用问题

Python 在引用计数机制的基础上,使用了主流垃圾收集技术中的标记——清除和分代收集两种技术。

推荐阅读