注: 本章测试代码在双核cpu的ubuntu系统下
单线程执行死循环
while True:
pass
执行上面代码,单线程死循环已经占满了一个cpu核
然后上面代码再次运行一份。 相当于同时运行2个 线程死循环 程序,我们看到俩个核全部被占满
多线程执行死循环
import threading
# 子线程死循环
def test():
while True:
pass
t1 = threading.Thread(target=test)
t1.start()
# 主线程死循环
while True:
pass
执行上面的代码,我们看到俩个核加起来的资源占有率是的一个的核的资源
由此,我们得出结论:
我们的多线程程序实际上是假的多任务
多进程执行死循环
import multiprocessing
# 子进程死循环
def test():
while True:
pass
t1 = multiprocessing.Process(target=test)
t1.start()
# 主进程死循环
while True:
pass
执行上面代码,我们看到俩个核都被占满
结论
当我们完成一项任务,使用了多线程,多进程。真正起到作用的是多进程,多线程其实是假的
GIL(全局解释器)
为什么线程是假的?
因为每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
Python语言运行需要解释器,通常我们用的,官网推荐的 是Cpython虚拟机解释器,由于历史也原因,难以移除。Cpython的作者曾经尝试去移除GIL,但是最终的效果没有GIL快,所以发布声明,同时也建议,如果你要发挥多核cpu的能力,就使用进程
那么问题来了:
编写一个多线程的爬虫程序,是否比单线程的要快?
答案是肯定的 多线程的爬虫程序比单线程的要快
这里要说说计算密集型程序 和 IO密集型程序
- 计算密集型: 直白点就是程序没有延时操作
- IO密集型: 程序执行中有读写操作,比较耗时
因为网络请求、文件读取等操作 就是典型的IO密集型操作 是耗时的,GIL可以充分利用这些空闲时间。所以多线程在比单线程快。
所以:
- 计算密集型: 用进程
- IO密集型: 用线程、携程
怎样克服GIL的问题
换掉Cpython解释器,用其他解释器
-
PyPy
PyPy是另一个Python解释器,它的目标是执行速度。PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),所以可以显著提高Python代码的执行速度。绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到PyPy下执行,就需要了解PyPy和CPython的不同点。
-
Jython
Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。 -
IronPython
IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
使用其它的语言(c/c++、java、javascript等)实现多线程代码,然后使用python去调用
python是胶水语言,可以很方便的调用其他语言