热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

pythongil解决_PythonGIL问题

Python‘最难’的问题——GIL问题一、什么是GILGIL(解释器全局锁)从名字上看能告诉我们很多东西,很显然,这是一个加在解释器上的全局(从解释器

Python‘最难’的问题——GIL问题

一、什么是GIL

GIL(解释器全局锁)

从名字上看能告诉我们很多东西,很显然,这是一个加在解释器上的全局(从解释器的角度看)锁(从互斥或者类似角度看)。

首先来看回顾一下什么是锁:

为什么加锁

由于多线程共享进程的资源和地址空间,因此,在对这些公共资源进行操作时,为了防止这些公共资源出现异常的结果,必须考虑线程的同步和互斥问题。

加锁的作用

1、用于非线程安全,2、控制一段代码,确保其不产生调度混乱。

GIL官方给出的解释

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

在CPython中,全局解释器锁(global interpreter lock, GIL)是一个互斥体,它防止多个本机线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的。(然而,自从GIL存在以来,其他特性已经逐渐依赖于它强制执行的保证。)

二、GIL的影响

GIL的设计缺陷

从上文的介绍和官方的定义来看,GIL就是一把全局排他锁。这种方式当然很安全,但是这对于任何Python程序来说,不管有多少的处理器,任何时候都总是只有一个线程在执行。毫无疑问全局锁的存在会对多线程的效率有不小影响。

但是我们课上讲的例子,并不是这样啊

上课的多线程例子:

from threading import Thread

import time

def task():

time.sleep(5)

def run():

t1 = Thread(target=task)

t2 = Thread(target=task)

start = time.time()

t1.start()

t1.join()

t2.start()

t2.join()

end = time.time()

print(f'Total time: {end - start}')

'''

串行结果:

Total time:10

'''

t1.start()

t2.start()

t1.join()

t2.join()

'''

并行结果:

Total time:5

'''

但是!

看看这个

from threading import Thread

import time

def counter():

# 计数到一亿

i = 0

for _ in range(100000000):

i += 1

return True

def run():

t1 = Thread(target=counter)

t2 = Thread(target=counter)

start = time.time()

t1.start()

t1.join()

t2.start()

t2.join()

end = time.time()

print(f'Total time: {end - start}')

'''

串行结果(即单线程):

Total time: 15.838918209075928

'''

t1.start()

t2.start()

t1.join()

t2.join()

'''

并行结果:

Total time: 16.79609990119934

(其实他们两个结果我跑的时候不相上下,但是也能说明问题)

'''

if __name__ == '__main__':

run()

问题来了。

为什么多线程并行比单线程慢,但是一些例子为什么多线程并行时间又更少?

刚刚也说了是因为GIL导致的,python解释器任何时候都是一个线程在执行。

一些情况下多线程并行快的原因是: 线程做的是i/o操作, 可以挂起当前线程去执行下一线程。因为遇到像 i/o操作这种 会有时间空闲情况 造成cpu闲置的情况会释放GIL

所以在python上只要在进行耗时的IO操作的时候,能释放GIL,这样也还是可以提升运行效率的。

为什么GIL有这个缺陷而不改进?

改不了!

为什么改不了

历史遗留问题:因为硬件的升级cpu单核变多核,当时python开发者为了利用多核,就出现了多线程编程,而随之带来的就是线程间数据一致性和状态同步的困难。 python开发者的解决方法就是加GIL这把大锁。

但是人们之后发现了这种多线程编程实现方式是垃圾的,想去除他,但是这时候已经发现离不开他了,大量的开发者已经重度依赖GIL了。

有了GIL的存在,python有这两个特点

1、进程可以利用多核,但是开销大。

2、多线程开销小,却无法利用多核优势。

也就是说Python中的多线程是假的多线程,Python解释器虽然可以开启多个线程,但同一时间只有一个线程能在解释器中执行,而做到这一点正是由于GIL锁的存在,它的存在使得CPU的资源同一时间只会给一个线程使用,而由于开启线程的开销小,所以多线程才能有一片用武之地,不然就真的是鸡肋了。

而python的多线程到底有没有用呢?

​有用。我们需要看任务是I/O密集型,还是计算密集型:

如果是I/O密集型任务,有再多核也没用,即能开再多进程也没用,所以我们利用python的多线程一点问题也没有;

如果是计算密集型任务,我们就直接使用多进程就可以了

如何解决GIL锁带来的问题

1、不用cpython,使用jpython(不太推荐)

2、使用多进程完成多线程任务(python专家推荐)

用multiprocess来代替Thread

multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。

但是它的引入会增加程序实现时线程间数据通讯和同步的困难。

3、使用多线程时用c语言实现



推荐阅读
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 在iOS开发中,多线程技术的应用非常广泛,能够高效地执行多个调度任务。本文将重点介绍GCD(Grand Central Dispatch)在多线程开发中的应用,包括其函数和队列的实现细节。 ... [详细]
  • 可参照github代码:https:github.comrabbitmqrabbitmq-tutorialsblobmasterjavaEmitLogTopic.ja ... [详细]
  • PBO(PixelBufferObject),将像素数据存储在显存中。优点:1、快速的像素数据传递,它采用了一种叫DMA(DirectM ... [详细]
  • vsftpd配置(虚拟用户、匿名用户登录)
    一、ftp服务搭建(一)概述1.ftp连接及传输模式(1)控制连接TCP21,用于发送FTP命令信息 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 本文详细介绍了Go语言中的数组,包括其基本概念、声明方式、初始化方法以及常见操作。 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
author-avatar
平凡小迪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有