单就视频来说,结论具有一定的误导性。这里的误导性是指视频中给出的结论需要更进一步指明前提条件,而这种前提条件受限于视频的长短,面向人群的知识储备的因素,在追求通俗易懂的目标下给出的不是那么地严谨容易对于知识储备不足的人群造成误导,忽略了结论的前提条件而错误应用。

  1. 关于协程的问题

首先,为什么要有协程?协程的产生是为了解决任务级并行问题下并行任务的指令流和数据上下文绑定,导致切换程序的指令流时不得不同时保存许多不必要的数据上下文,从而产生了性能瓶颈的问题。

任务级并行,简单地说就是在相对固定的硬件设备上(如固定数目的CPU, 固定的内存,为了叙述的方便,这里假设为单个单核CPU)通过不断地切换在其上运行的任务(Task)从而达到并行的手段。所谓任务,包含了两部分,一部分是任务本身要执行的指令,另一部分是执行这些指令所需要的上下文(此处借用了Mach微内核论文中的概念)。指令流的切换主要依靠中断和操作系统调度,上下文的切换依赖虚拟内存和操作系统保存任务用到的各种寄存器。这个任务在经典的操作系统中通常被实现为我们所熟知的进程(Process),进程切换时需要同时切换指令流和上下文。可是在某些情况下,我们希望共享部分上下文,如共享虚拟内存空间。这样,我们就得到了相对轻量的另一种任务级并行手段线程(Thread)。可是,即便是线程,依然需要保存大量的寄存器,同时由操作系统调度,这一过程不受用户控制,因此未必能达到最佳性能。

协程(Coroutine)的出现将任务切换的上下文进一步地减少,在进行协程切换时,只需要保存更少的寄存器,从而节约了大量的内存,提高了切换的效率。另一方面,协程实现在用户态,协程切换的调度过程可以由用户控制。从操作系统内核的角度看来,它是发现不了协程的。操作系统内核看到的,只是一个普通的进程。为了方便理解,极为不严谨地说,协程的切换与普通函数调用是类似的。因为函数调用实际上需要保存一定的上下文(要返回的指令位置),然后跳转到新的指令位置。协程比它的上下文稍微多一些,还可以调度,但是实现上是类似的。(要有更深的理解,可以参考Go语言实现中的PMG模型)

因为协程减少了无关的上下文切换,本身的调度可以受用户控制。因此,在优良设计的前提下,协程能够提供更强的任务级并行。这也是视频中所说的,在别的才支持1k个的时候,协程可以支持100万个的理由。

要注意,协程是一个概念,它本身可以用各种各样的编程语言实现。那这一切和Python有何关系?猜测作者的意思,一是Python本身在协程方面起步早,有大量成熟的协程框架,设计优良。二是Python本身易于编写,有助于程序员提高开发效率,有时候易于写出优良的代码。因此,Python借助协程而快。

然而,这一说法存在误导性。因为首先并不是所有的问题都可以通过任务级并行加速,这也是视频作者说的IO密集型和计算密集型的区分。其次,也并非其他语言不可能有更好的协程框架。因此,Python并不是永远都会因为协程获得比其他语言更大的执行效率上的优势,这一点是值得注意的。

2. 关于PyPy的问题

首先PyPy的原理是所谓的Meta Tracing。即为我们所熟知的静态强类型编译型语言(极为不严谨的说法,下同),如C, C++等,它们往往都是AOT(Ahead of Time) 预先静态编译的,因为源代码本身提供的大量有帮助的类型信息,且变量的类型不会轻易地改变,因此可以在程序执行之前编译成为机器码提高执行效率。另一些动态弱类型解释型语言,如Python, JavaScript等,由于源代码本身缺乏类型信息,变量的类型可以动态的改变,编译器不到运行时很难知道足够的信息,无法编译到机器码,只能JIT(Just in Time)即时编译,因为在运行时刻各类信息全了,对于反复执行的热点代码,可以编译为机器码加速。对于一般的动态语言,其实在运行时刻的程序包含两部分,一是被解释执行的程序,二是解释器。传统的JIT一般只追踪被解释执行的程序的反复执行的热点部分,将它编译为机器码,其他部分交给解释器解释执行。PyPy所采用的Meta Tracing,即元追踪,会追踪解释器本身,即多了一层追踪,将解释器反复执行的热点代码进行JIT优化,这样就可能产生更优的性能,这是PyPy拥有卓越性能的关键。具体可以参考Tracing the Meta-Level: PyPy's Tracing JIT Compiler一文。PyPy相对来说无论概念上还是实现上是比较复杂的。

视频中所说的PyPy是用Python本身实现的,这一说法也不够严谨,PyPy是用RPython这一限制了Python的动态性后得到的Python子集实现的(当然也可以用Python实现,RPython是子集嘛,但这样就慢了。因为限制了动态性,所以能够更好地JIT,这也是PyPy性能卓越的关键。不过这恰恰说明不了Python的性能优势,毕竟如果Python本身性能就足够好,那为啥还要专门限制一下取子集呢

用PyPy来论证Python性能优势,其实是有问题的。正因为Python本身的性能有问题,不够快,才会有PyPy相对复杂的这套做法,最后做出一个比较快的实现,这其实反映了Python在性能上不那么出众。

综上,这个视频从Python宣传的角度来讲是不错的,但是要说Python是最快的语言,那还是得加很多前提条件的。如果有可能,视频的观看者应该多学一些。如果有机会,视频的作者可以多说一些。这样会更好。