Python高级语法1:GIL锁&浅拷贝&深拷贝

简介: Python高级语法1:GIL锁&浅拷贝&深拷贝

一、GIL锁


  • 1.1、GIL面试题:描述Python GIL的概念, 以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因。
  • Guido的声明: he language doesn't require the GIL -- it's only the CPython virtual machine that has historically been unable to shed it.


  • 1.2、参考答案:


  • (1)、Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。
  • (2)、GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
  • (3)、线程释放GIL锁的情况: 在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
  • (4)、Python使用多进程是可以利用多核的CPU资源的。
  • (5)、多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁


二、浅拷贝


  • 2.1、浅拷贝是对于一个对象的顶层拷贝,简单的理解是:拷贝了引用,并没有拷贝内容
  • 2.2、 看一个最简单的浅拷贝


image.png


  • 以上:a 与 b 的内存地址相同,说明了当给一个变量赋值的时候,其实就是将数据的引用赋值了一份给另外一个变量,这其实就是最简单的浅拷贝,不仅列表是这样,只要是 类似于 xx1 = xx2 的这种基本都是 浅拷贝,如下:


>>> c = {"age":23}
>>> d = c
>>> id(c)
4527333240
>>> id(d)
4527333240
>>> c["name"] = "王小二"
>>> c
{'age': 23, 'name': '王小二'}
>>> d
{'age': 23, 'name': '王小二'}
  • 因为都是浅拷贝,所以只要通过一个引用进行了修改,那么另外一个变量就看到的数 据也就变化了


  • 2.3、import copy 模块中 copy.copy() 的使用


>>> a = [11,22]
>>> b = [33,44]
>>> c = [a,b]
>>> id(a)
4528760776
>>> id(b)
4528427464
>>> id(c)
4528012488
>>> import copy
>>> d = copy.copy(c)
>>> id(d)
4528788488
>>> id(d[0])
4528760776
>>> id(d[1])
4528427464
>>> a.append(55)
>>> c
[[11, 22, 55], [33, 44]]
>>> d
[[11, 22, 55], [33, 44]]


image.png


浅拷贝 只会复制最顶层的那个列表


三、深拷贝



  • 3.1、深拷贝是对于一个对象所有层次的拷贝(递归)


>>> a = [11,22]
>>> b = copy.deepcopy(a)
>>> a
[11, 22]
>>> b
[11, 22]
>>> id(a)
4528761928
>>> id(b)
4528933000
  • 以上结果通过deepcopy()确实将列表 a 中所有的数据的引用  copy 了,而不是只拷贝了 a 指向的列表的引用,看如下,a的数据发生变化的时候,b并不会发生变化


>>> a.append(55)
>>> a
[11, 22, 55]
>>> b
[11, 22]


3.2、进一步理解 深拷贝

image.png


  • 深拷贝:  我个人理解其实是:深拷贝后与原来的对象没有任何关系了,不管原来的对象如何变化,都不再会影响到深拷贝后的对象


四、拷贝的其他方式



  • 4.1、分片表达式 可以赋值一个序列


>>> a = [11,22]
>>> b = [33,44]
>>> c = [a,b]
>>> d = c[:]
>>> id(c)
4528760776
>>> id(d)
4528932936
>>> id(c[0])
4528933000
>>> id(d[0])
4528933000
>>> a
[11, 22]
>>> a.append(55)
>>> c
[[11, 22, 55], [33, 44]]
>>> d
[[11, 22, 55], [33, 44]]



image.png



d=c[:]d=copy.copy(c) 一样 属于 浅拷贝


  • 4.2、字典的copy方法可以拷贝一个字典


image.png


五、注意点



  • 5.1、浅拷贝对不可变类型和可变类型的copy不同
  • copy.copy 对于 可变类型,会进行浅拷贝


>>> a = [11,22]
>>> b = copy.copy(a)
>>> id(a)
4528932552
>>> id(b)
4528932680
>>> a.append(33)
>>> a
[11, 22, 33]
>>> b
[11, 22]
  • 解释一下大家的对于a变化,而b不变化的问题,因为b拷贝的是a里面 11,22引用的指向,当a添加 33的时候,而 11,22引用的指向并没有发生变化,所以并不会发生变化


  • copy.copy 对于 不可变类型,不会拷贝,仅仅是指向


>>> a = (11,22,33)
>>> b = copy.copy(a)
>>> id(a)
4528768632
>>> id(b)
4528768632
  • 如果c是元组,那么copy时会,仅仅是元组的引用copy,而 deepcopy依然是深copy,即递归copy所有


>>> a = [11,22]
>>> b = [33,44]
>>> c = (a,b)
>>> d = copy.copy(c)
>>> id(c)
4528885256
>>> id(d)
4528885256
>>> a.append(55)
>>> c
([11, 22, 55], [33, 44])
>>> d
([11, 22, 55], [33, 44])
>>> e = copy.deepcopy(c)
>>> id(c)
4528885256
>>> id(e)
4528885448
>>> a.append(66)
>>> c
([11, 22, 55, 66], [33, 44])
>>> e
([11, 22, 55], [33, 44])
>>>
  • 5.2、copy.copy和copy.deepcopy的区别
  • copy.copy


>>> a = [11,22]
>>> b = (a,)
>>> c = [b,]
>>> 
>>> d = copy.copy(c)
>>> 
>>> c
[([11, 22],)]
>>> d
[([11, 22],)]
>>> a.append(33)
>>> c
[([11, 22, 33],)]
>>> d
[([11, 22, 33],)]
>>> id(c)
4528932936
>>> id(d)
4528012488
>>> id(c[0])
4528434200
>>> id(d[0])
4528434200


image.png



d = c # 让d这个变量指向c指向的空间,d = copy.copy(c) # 复制所有c指向的数据到一个新的空间,但是不会递归copy


  • copy.deepcopy


>>> a = [11,22]
>>> b = (a,)
>>> c = [b]
>>> 
>>> d = copy.deepcopy(c)
>>> 
>>> c
[([11, 22],)]
>>> d
[([11, 22],)]
>>> 
>>> id(c)
4528932680
>>> id(d)
4528761928
>>> 
>>> id(c[0])
4528913040
>>> id(d[0])
4528913096
>>> 
>>> a.append(33)
>>> 
>>> c
[([11, 22, 33],)]
>>> d
[([11, 22],)]
>>>


image.png


image.png

目录
相关文章
|
1天前
|
人工智能 Ubuntu IDE
【Python】基础:环境配置与基础语法
本文介绍了Python编程语言及其环境配置方法。Python由Guido van Rossum于1991年创建,以其简洁、易学和强大的功能著称。文章详细讲解了Python的主要特点、Windows和Ubuntu下的安装配置步骤、基础语法、控制流、函数、文件操作、模块使用及面向对象编程等内容,帮助读者快速入门Python编程。
14 4
|
18天前
|
存储 C语言 索引
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
本文全面介绍了Python的基础知识,包括Python的诞生背景、为什么学习Python、Python的应用场景、Python环境的安装、Python的基础语法、数据类型、控制流、函数以及数据容器的使用方法,旨在为Python零基础读者提供一篇全面掌握Python语法的博客。
22 0
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
|
19天前
|
存储 数据可视化 数据处理
【Python篇】快速理解Python语法:全面指南
【Python篇】快速理解Python语法:全面指南
21 1
|
28天前
|
Java Linux C++
30天拿下Python之基础语法
30天拿下Python之基础语法
23 4
|
1月前
|
IDE Java 开发工具
Python的语法
Python的语法。
27 5
|
2月前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
18天前
|
Java C语言 Python
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
26 0
|
1月前
|
存储 数据挖掘 程序员
揭秘Python:掌握这些基本语法和数据类型,你将拥有编程世界的钥匙!
【9月更文挑战第3天】Python 是一种简洁强大的高级编程语言,其清晰的语法和丰富的功能深受程序员喜爱。本文从基本语法入手,介绍 Python 的代码结构特点,如通过缩进区分代码块,使逻辑更清晰。接着详细讲解主要数据类型:数值型、字符串、列表、元组、集合与字典,每个类型均附有示例代码,帮助初学者快速掌握 Python,为后续学习打下坚实基础。
38 2
|
1月前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
22 0
|
2月前
|
IDE Java 测试技术
Python接口自动化测试框架(基础篇)-- 基础语法(真的很基础)
这篇文章是关于Python编程语言的基础语法介绍,包括编码、标识符、注释、行和缩进、输入输出以及导包等基础知识点,旨在帮助初学者理解并掌握Python编程的基础。
22 2