Python中的全局解释器锁(GIL)是什么

Python中的全局解释器锁(GIL)是什么

本教程将重点讲解Python中的一个重要主题——GIL(全局解释器锁)。我们还将介绍GIL如何影响Python程序的性能,并提供代码实现。在深入探讨这个主题之前,让我们首先了解一下GIL的基本概念。

GIL或全局解释器锁

Python的全局解释器锁(GIL)是多线程编程中的一个重要部分。它是在使用多个进程时使用的一种进程锁类型。它只允许一个线程进行控制。通常,Python使用单个线程来运行单个进程。使用GIL,我们可以获得单线程和多线程进程相同的性能结果。它限制了Python中实现多线程的能力,因为它阻止了多线程并且作为一个单一的线程工作。

注意:Python不支持多线程,因为线程包不能让我们使用多个CPU核心。

为什么Python开发人员使用GIL

Python提供了独特的引用计数器特性,用于内存管理。引用计数器计算Python内部对数据对象赋值时所做的引用总数。当引用计数达到零时,释放对象的分配内存。让我们看下面的示例。

示例

import sys
a = []
b = a
sys.getrefcount(a)

参考计数变量的主要问题在于,当两个或三个线程试图同时增加或减少其值时,它可能会受到影响。这被称为竞争条件。如果发生这种情况,可能会导致泄漏的内存永远不会释放。它可能会导致Python程序崩溃或出现错误。

GIL通过对所有共享数据结构使用锁来帮助我们消除这种情况,以避免它们不一致地改变。Python提供了一种简单的方式来实现GIL,因为它处理了线程安全的内存管理。GIL需要为Python中的线程提供一个单一锁来进行处理。它提高了单线程程序的性能,因为只需要处理一个锁。它还有助于使任何CPU密集型程序,并防止死锁条件。

对多线程Python程序的影响

对于典型的Python程序或任何计算机程序,CPU密集型和I/O密集型之间有性能上的区别。CPU密集型程序通常会推动CPU到其极限。这些程序通常用于数学计算,例如矩阵乘法、搜索、图像处理等。

I/O密集型程序是那些需要花费时间获取用户、文件、数据库、网络等生成的输入/输出的程序。这样的程序必须等待一段相当长的时间,直到源提供输入。另一方面,源也有自己的处理时间。例如,用户正在考虑输入什么。

让我们理解以下示例。

示例

import time
from threading import Thread
COUNT = 100000000

def countdown(num):
    while num>0:
        num -= 1

start_time = time.time()
countdown(COUNT)
end_time = time.time()

print('Time taken in seconds -', end_time - start_time)

输出:

Time taken in seconds - 7.422671556472778

现在我们通过运行两个线程来修改上面的代码。

示例2:

import time
from threading import Thread

COUNT = 100000000

def countdown(num):
    while num>0:
        num -= 1

thread1 = Thread(target=countdown, args=(COUNT//2,))
thread2 = Thread(target=countdown, args=(COUNT//2,))

start_time = time.time()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
end_time = time.time()
print('Time taken in seconds -', end_time - start_time)

输出:

Time taken in seconds - 6.90830135345459

正如我们所看到的,两段代码完成的时间相同。GIL阻止了第二段代码中CPU绑定的线程并行执行。

为什么GIL还没有被移除呢

许多程序员对此表示不满,但Python无法进行像移除GIL这样重大的更改。另一个原因是目前GIL没有得到改进。如果在Python 3中改变,将会产生严重的问题。与其移除GIL,不如改进GIL的概念。根据Guido van Rossom的说法:

“我将欢迎一组补丁进入Py3k,前提是对于单线程程序(以及多线程但I/O密集型程序)的性能没有降低”。

还有许多方法可用于解决GIL解决的同样问题,但是它们很难实现。

如何处理Python的GIL

使用多进程是防止程序受到GIL影响的最合适的方法。Python为每个进程提供了各种解释器来运行,因此在这种情况下,每个进程被分配一个单线程。让我们来理解以下示例。

示例

from multiprocessing import Pool
import time

COUNT = 50000000
def countdown(num):
    while num>0:
        num -= 1

if __name__ == '__main__':
    pool = Pool(processes=2)
    start_time = time.time()
    r1 = pool.apply_async(countdown, [COUNT//2])
    r2 = pool.apply_async(countdown, [COUNT//2])
    pool.close()
    pool.join()
    end_time = time.time()
    print('Time taken in seconds -', end_time - start_time)

输出:

Time taken in seconds - 3.3707828521728516

这可能会增加一定的性能,但是处理进程有自己的开销,多个进程比多个线程要重。

结论

在本教程中,我们讨论了全局解释器锁(GIL)以及如何使用它。它将控制权交给单个线程以执行。本教程还介绍了为什么对于Python程序员来说GIL很重要。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程