python是动态类型解释性语言,不管使用哪种解释器
因为“解释性语言”这个概念更多地是指代码的执行方式,而不是编译方式。在解释性语言中,代码在执行时会一行一行地解释并执行,而不是预先编译为机器语言。而即使使用了PyPy解释器,PyPy使用了JIT(即时编译)技术,它会在代码运行时将代码编译为机器语言。其中的JIT编译技术仍然在运行时进行,代码仍然在运行时动态确定类型和解释执行。因此,尽管PyPy使用了编译技术加速代码的执行,但它仍然是解释性语言
动态语言(python)的运行速度为什么比静态语言(java)慢?
在 Java 和 Python (cpython解释器)中,都存在先编译为字节码,然后再在解释器或虚拟机中将字节码转换为机器语言的过程。那么为什么 Java 的运行速度会比 Python 快,python在运行时动态确定类型和进行解释会比java慢
静态类型的语言比如 C,Java,Go,需要在声明变量的时候带上类型。而 Python 就不用,Python 帮你决定一个变量是什么类型,并且可以随意改变。
动态类型为什么慢呢?每次检查类型和改变类型开销太大;如此动态的类型,难以优化
Python 的动态类型和动态内存分配也会对运行速度产生影响。Python 中的对象都是动态创建的,这就需要在运行时进行内存分配和回收,这会比静态分配更慢。
pypy解释器的大致运行过程
PyPy解释器既是解释性的,也是编译性的。
在PyPy解释器中,源代码首先会被编译成抽象语法树(AST),然后被编译成LLVM IR(Intermediate Representation,中间表示)。接着,LLVM IR会被传递给JIT编译器,生成对应的机器码,这些机器码被缓存起来以备下次调用(注意这里是在pypy解释器中的过程,而只有在运行代码的时候才会去用pypy解释器去解释)。这个过程中,JIT编译器根据实际情况来选择是否对代码进行即时编译。如果发现某些代码被重复执行(如循环),JIT编译器会对这些代码进行优化并将它们编译成机器码,以提高程序性能。如果当 JIT 编译器无法对代码进行优化时,PyPy 仍然会使用解释器来执行 Python 代码。
因此,PyPy解释器既包含解释器的特点,也包含编译器的特点。在运行过程中,PyPy解释器会将源代码解释执行,同时也会将部分代码编译成机器码,以提高程序性能。因此,可以说PyPy是一种混合型的解释器/编译器。
首先GIL锁是python 默认的cpython解释器带的,在此解释器下创建多线程是用户级线程,且cpython的多线程模型是多对一模型,即使你创建再多的多线程,也只会被映射到一个内核级线程上,内核级线程去排对竞争cpu。
因为即使是多对多模型,python代码创建多个线程(用户级线程)最终被映射到了多个内核级线程上,然后这些内核级线程去排队竞争cpu,假设同时竞争到了cpu时间片,但是也只有一个内核线程有GIL锁,才能调用cpython解释器将python字节码解释成机器码执行,而那些没有GIL锁的内核线程即使分配到了cpu时间片,会发现没有GIL锁,无法调用cpython解释器,因此也就无法执行字节码,从而又被系统放入到阻塞队列中去等待GIL锁的资源。
即同一时刻只能有一个内核线程获取GIL锁然后被解释器解释执行,那么其它的内核线程就会增加操作系统调度和上下文切换的开销,而没有实际的性能提升。
GIL锁的存在是为了保证解释器的线程安全性。因为CPython的解释器内部实现使用了大量的全局变量和共享数据结构,如果没有GIL锁的保护,多个线程同时访问这些数据结构会导致解释器的崩溃或者产生未定义的行为。通过GIL锁的机制,CPython确保了在任意时刻只有一个线程可以执行解释器的字节码,从而保证了解释器的线程安全性。