第37条 线程执行阻塞式I/O,但不能用来做平行计算

标准的Python实现叫做CPythonCPython分两步用来运行Python程序:

  • 1.首先,将文本形式的源代码解析并编译成字节码;
  • 2.然后,用一种基于栈的解释器运行这份字节码。

执行Python程序时,字节码解释器必须保持协调一直的状态。Python采用全局解释器锁(GIL)机制来实现这种协调性。

GIL实际上是一把互斥锁,用来防止CPython受到抢占式多线程切换操作的干扰。但是,GIL有一个显著的缺点在于,C++Java等语言的多线程程序可以充分利用CPU的多核,而Python编写的多线程程序,受到GIL保护,同一时刻,只有一条线程可以执行

案例1:利用Python进行因数分解算法。

from time import  time

def factorize(number):
    for i in range(1, number+1):
        if number % i == 0:
            yield i
            
if __name__ == '__main__':
    numbers = [2149000, 3902300, 8390202, 10008375]
    start = time()
    for number in numbers:
        list(factorize(number))
    end = time()
    print("Spend time %.3f seconds" % (end-start))

输出结果:

Spend time 2.022 seconds

改成使用Python的多线程程序:

from threading import Thread
from time import time

def factorize(number):
    for i in range(1, number+1):
        if number % i == 0:
            yield i
            
class FactorizeThread(Thread): ##继承Thread
    def __init__(self,number):
        super().__init__()
        self.number = number
    def run(self):
        self.factors = list(factorize(self.number))
        
if __name__ == '__main__':
    numbers = [2149000, 3902300, 8390202, 10008375]
    start = time()
    threads = []
    for number in numbers:
        thread = FactorizeThread(number)
        thread.start()
        threads.append(thread)
        
    for thread in threads:
        thread.join()
        
    end = time()
    print('Spend time %.3f seconds' %(end-start))

输出结果:

Spend time 2.570 seconds

可以看出,多线程程序执行所花费的时间竟然更长。这样的结果表明,标准的CPython解释器的多线程程序受到GIL的影响。

尽管Python的多线程很鸡肋,但是仍然可以应用在阻塞式的IO操作中,例如读写文件,网络通讯等操作。同时,Python在多个线程中执行系统调用时,其可以实现平行地执行。Python线程在执行系统调用的时候会释放GIL锁,并且一直等到执行完毕才会重新获取它,所以GIL是不会影响系统调用的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章