python 深入了解GIL锁详细

Python深入了解GIL锁

什么是GIL锁?

GIL全局解释器锁(Global Interpreter Lock),是Python解释器的一种机制。在Python多线程执行的时候,由于GIL锁的存在,同一时间只有一个线程能够执行,其他的线程只能在等待队列中等待。

GIL锁的存在意义

在解释Python代码的时候,Python会将解释器内存中的字节码编译成对底层处理器指令的解释器程序。由于Python具有便捷易用的GIL(Global Interpreter Lock)线程锁,这意味着在任何时候只能有一个线程从你的程序中运行Python代码。

这个锁的存在使得Python的多线程执行得以实现,但在某些情况下也可能会阻止Python的多线程执行。

Python实现线程的方式

Python实现线程的方式有两种:Thread对象和对于多线程执行优化的Thread Pool

  • Thread对象:主要用于短期的线程调用,例如APIs,即在你使用APIs访问外部资源的时候,Python将会使用线程调用,但是在执行你的应用程序的主体时依旧必须采用单线程执行方式。

  • Thread Pool:因为它们复用现有的线程对象,所以与“Thread”对象相比,这种执行方法在处理长时间运行的操作(例如数据I/O)方面更加优越

GIL锁的优劣

优势:

  • GIL锁让对于Python 的多线程执行的管理变得更加简单而可行。

  • GIL锁可以实际上确保Python代码的安全性。

弊端:

  • 在“密集计算”(CPU-bound)情况下,Python 使用线程模型可能会在运行时花费更多的时间。

  • 在“io处理”(I/o-bound)情况下,Python使用线程时,多线程执行的效率可能会比单线程略快,但是使用100个线程通常比使用10个线程要慢得多!

示例说明

为了更好地理解Python GIL锁的机制,下面的示例说明将创建两个线程并测量它们在同时运行时的效率。

import threading
from datetime import datetime

def job(n):
    print(f'{n} starts!')
    for i in range(n):
        pass
    print(f'{n} ends!')

start_time = datetime.now()

# 创建两个线程
t1 = threading.Thread(target=job, args=(100000000,))
t2 = threading.Thread(target=job, args=(100000000,))

# 启动两个线程
t1.start()
t2.start()

# 等待两个线程结束
t1.join()
t2.join()

end_time = datetime.now()
print(f'Time cost: {end_time - start_time}')

运行结果如下:

1 starts!
2 starts!
1 ends!
2 ends!
Time cost: 0:00:04.104312

我们可以看到,尽管我们使用了两个线程,但是它们却是一个接一个地运行的。因为即使在运行多线程的情况下,Python的GIL锁仍然保证只有一个线程在执行。

现在我们再看一个I/O密集型的例子,使用Python的concurrent.futures模块中的ThreadPoolExecutor类实现多线程执行。以下代码从50个网站下载图标,并测量了每次请求的时间和总时间。

import requests
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime

urls = [
    'https://www.github.com/favicon.ico',
    'https://www.python.org/favicon.ico',
    'http://www.cnblogs.com/favicon.ico',
    'http://c.biancheng.net/favicon.ico',
    'https://www.baidu.com/favicon.ico',
    'https://www.sina.com.cn/favicon.ico',
    'http://www.tmall.com/favicon.ico',
    'https://www.jd.com/favicon.ico',
    'http://www.pku.edu.cn/favicon.ico',
    'http://www.fudan.edu.cn/favicon.ico'
]

def download_one(url):
    img = requests.get(url)
    print(f'Download from {url}, and save it.')
    return url

start_time = datetime.now()

with ThreadPoolExecutor(max_workers=5) as executor:
    for url in urls:
        executor.submit(download_one, url)

end_time = datetime.now()
print(f'Time cost: {end_time - start_time}')

运行结果如下:

Download from http://www.cnblogs.com/favicon.ico, and save it.
Download from https://www.baidu.com/favicon.ico, and save it.
Download from https://www.jd.com/favicon.ico, and save it.
Download from https://www.github.com/favicon.ico, and save it.
Download from http://c.biancheng.net/favicon.ico, and save it.
Download from http://www.tmall.com/favicon.ico, and save it.
Download from https://www.sina.com.cn/favicon.ico, and save it.
Download from https://www.python.org/favicon.ico, and save it.
Download from http://www.fudan.edu.cn/favicon.ico, and save it.
Download from http://www.pku.edu.cn/favicon.ico, and save it.
Time cost: 0:00:01.405767

我们可以看到,这个例子中多线程的效率比单线程快得多,原因是因为它是一个I/O密集型操作,而不是一个CPU密集型操作。在这种情况下,Python多线程执行的效率通常比单线程更高。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python 深入了解GIL锁详细 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言中如何进行GUI编程?

    要在C语言中进行GUI编程,需要使用专门的库或框架。以下是两种常用的GUI编程方式: 1. 使用GTK+库进行GUI编程 GTK+是一个跨平台的开源GUI库,它基于C语言编写。使用GTK+编写GUI程序的基本步骤如下: 步骤一:安装GTK+库 在Ubuntu系统下,可以输入以下命令安装GTK+库: sudo apt-get install libgtk2.0…

    C 2023年4月27日
    00
  • 详解C语言中的fopen()函数和fdopen()函数

    下面就详细讲解一下“详解C语言中的fopen()函数和fdopen()函数”。 fopen()函数 fopen()函数的基本介绍 fopen()是C语言中用于打开文件的库函数,通过它可以打开一个文件并返回一个文件指针。其函数原型为: FILE *fopen(const char *filename, const char *mode); 其中,filenam…

    C 2023年5月23日
    00
  • 如何编译libfreetype方法详解

    下面是如何编译libfreetype的方法详解: 1. 下载并解压libfreetype源码包 官网下载链接:https://sourceforge.net/projects/freetype/files/freetype2/2.11.0/freetype-2.11.0.tar.gz/download 解压命令:tar -zxvf freetype-2.11…

    C 2023年5月23日
    00
  • Python 操作SQLite数据库详情

    下面我将为你讲解如何在 Python 中操作 SQLite 数据库。 什么是 SQLite 数据库 SQLite 是一种开源的轻型关系型数据库管理系统,其特点是占用资源非常少、使用简单、速度快。它不需要独立的服务器进程,也不需要配置和管理。因此,SQLite 适用于在客户端存储数据,例如手机 App 中存储本地数据。 安装 SQLite 在 Python 中…

    C 2023年5月23日
    00
  • C语言基础使用IDE快速开发的方法

    当我们学习C语言的时候,我们需要一个充足的开发环境去快速的开发我们的代码,而IDE(Integrated Development Environment)即为一种能够提供编码功能、调试功能等等一系列开发过程中需要的整合化开发环境。在下面的步骤中,我将会给大家讲解如何在IDE环境下使用C语言进行快速开发。 步骤一:安装IDE 安装IDE环境是IDE使用的第一步…

    C 2023年5月22日
    00
  • c++11中关于std::thread的join的详解

    简介 在C++11中,我们可以通过std::thread类来创建一个线程。该类提供了与操作系统级别的线程相关的方法,例如创建、销毁、挂起、恢复等。线程的执行中,有可能会出现多个线程共享同一个资源导致的竞争情况,此时,我们就需要对线程进行同步,在正确的时间点上对多个线程进行操作控制。join函数就是一个非常常用的同步方法。 使用方法 join函数用于等待线程的…

    C 2023年5月22日
    00
  • javascript表单域与json数据间的交互

    下面是关于“javascript表单域与json数据间的交互”的完整攻略。 1. 什么是JSON? JSON(JavaScript Object Notation)是一种轻量级数据交换格式,原本用来代替XML,现在已成为一种独立的数据格式。它以键/值对的形式来表示数据,常用于传输数据,在客户端和服务器之间进行数据交互。 JSON 格式的数据可以是文本、数字、…

    C 2023年5月23日
    00
  • C++11 并发指南之std::mutex详解

    C++11 并发指南之std::mutex详解 什么是std::mutex? std::mutex是C++11标准中一个用于保护共享数据的同步原语。它是一个轻量级的锁,可以用于实现临界段或者锁保护的互斥访问。当一个线程执行到std::mutex的lock()方法时,如果此前该锁已经被另一个线程占用,那么该线程会被挂起,直到该锁被释放为止。 std::mute…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部