活动地址:CSDN21天学习挑战赛
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…
目录
一、GIL锁
1.概念
GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
2.和python的关系
Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。
3.表现
多线程本身是一个假的多任务,真正的多任务完成并发---多进程
导致他们这样的差异的主要是GIL(全局解释器锁)---保证多线程的程序同一时刻只有一个线程在执行
单线程死循环----一个进程占满一个cpu核
2个线程死循环-----每一个核占50%一共2个核,没有发挥多核概念。
2个进程死循环----占满两个cpu核,一个程序一个核发挥了多核的功能。
cpython---存在GIL--每个线程在执行时都会先获取GIL上锁保证同一时刻只有一个任务在做。
4. 疑惑
那么多线程会比单线程快为什么
单线程如爬虫进行recv时会堵塞直到接收了才进行下一个
而多线程recv堵塞的时候把这个堵塞的时间用来做另一个事情从而提高了效率
5.如何克服
克服GIL:
换解释器
换语言(指的是通过python执行其他语言,直接调用,反正不适用python解释器就行)
二、深拷贝、浅拷贝
1.概念
拷贝即复制
深拷贝浅拷贝区别在于----->复制的多少浅拷贝:对于一个对象的顶层拷贝
深拷贝:深拷贝是对于一个对象所有层次的拷贝(递归)
copy.deepcopy()---完成深拷贝
copy.copy()---浅拷贝
2.浅拷贝
a.最简单的浅拷贝
a = 1
b = a
print(id(a))
print(id(b))
# 1674914627824
# 1674914627824
结果为a的内存地址和b的相同说明了b=a来给b赋值的时候是把a的引用传给了b这就是最简单的浅拷贝,大多数类似的赋值都是如此。
a = 1
b = a
print(id(a))
print(id(b))
a = 2
print("b的值为:", b)
print("a的地址", id(a))
print("b的地址:", id(b))
b.浅拷贝案例
import copy
a = [11, 22]
b = [33, 44]
c = [a, b] # 开辟一个空间存一个列表元素为ab的地址引用。
d = c # 没有开辟空间只是把c的地址引用给了d
e = copy.copy(c) # 完成浅拷贝, 即只拷贝一层你要我拷贝c我把c里面的拷贝给e但是c里的a b不变
print("d的地址", id(d)) # d的地址 2337135078784
print("c的地址", id(c)) # c的地址 2337135078784
print("e的地址", id(e)) # e的地址 2337135079488
# 上面已经说明e开辟新的空间拷贝了c,然而e里面的a b也是开辟新的空间吗
print("对于c里面来说a的地址为", id(c[0])) # 2337138033344
print("对于e里面来说a的地址为", id(e[0])) # 2337138033344
浅拷贝:即只拷贝了最外面一层,如上式可知你叫我拷贝c所以开辟新的空间成e.然后c里面有元素,对于此e是如何处理的呢?是将c里面的元素全部开辟新的空间吗?从结果上来看并不是,它只是拷贝了c里面元素的引用放于e里面。
3.深拷贝
import copy
a = [11, 22]
b = [33, 44]
c = [a, b] # 把a b 的引用放进去
d = c
e = copy.deepcopy(c) # 深拷贝:把c里面ab的值也开辟了空间
print("对于c里面来说a的地址为", id(c[0])) # 对于c里面来说a的地址为 1830523978432
print("对于e里面来说a的地址为", id(e[0])) # 对于e里面来说a的地址为 1830523986432
和浅拷贝里面的进行对比结果很明显,深拷贝把里面所有的数据都再开辟了空间,而不是拿着原来的引用。
4.深拷贝和浅拷贝
import copy
a = [11, 22]
b = [33, 44]
c = [a, b]
d = copy.deepcopy(c) # 深拷贝
e = copy.copy(c) # 浅拷贝
print(id(c))
print(id(d))
print(id(e))
"""
2289709231616
2289709232000
2289711933696
"""
也许你会被绕进去为什么c和e的地址不一样?
请不要忘记浅拷贝对于最外面的那一层也是开辟新的空间。
三、浅拷贝、深拷贝拓展
1.元组
a
import copy
a = (11, 22)
b = copy.copy(a)
c = copy.deepcopy(a)
print(id(a))
print(id(b))
print(id(c))
"""
2491448630976
2491448630976
2491448630976
"""
用copy去拷贝元组(不可变类型)---不会进行浅拷贝或深拷贝仅仅是拷贝指向,反正元组是不会改变的你再重新创建空间有啥用,所以他会判断然后只拷贝引用
b
import copy
a = [11, 22]
b = [33, 44]
c = (a, b)
d = copy.deepcopy(c)
e = copy.copy(c)
print(id(c)) # 3259965272640
print(id(d)) # 3259967824192
print(id(e)) # 3259965272640
对于最外层是元组如果里面都是不可变类型那么拷贝时不管你是用深拷贝还是浅拷贝结果都是拷贝引用
但是如果里面有可变类型进行浅拷贝时依然只拷贝引用,但是深拷贝时一定会全部重新创建
2.切片
a = [11, 22]
b = [33, 44]
c = [a, b]
d = c[:]
print(id(c)) # 1628679454784
print(id(d)) # 1628677242304
print(id(c[0])) # 1628676550592
print(id(d[0])) # 1628676550592
从结果上来看切片操作和前copy一样只拷贝表层
3.字典
d = dict(name="张三", age="10")
co = d.copy()
print(id(co))
print(id(d))
#3171495622208
#3171495622400
# 在字典里面value是以引用的方式存在
# 字典进行copy,得到的是浅拷贝,他们字典的value是共享的
在字典里面value是以引用的方式存在
字典进行copy,得到的是浅拷贝,他们字典的value是共享的
4.函数
import copy
def test(temp):
temp.append(33)
num = [11, 22]
test(num)
print(num) # [11, 22, 33]
test(copy.deepcopy(num))
print(num) # [11, 22, 33]
四、预告
明天进行私有属性,继承封装多态的深入知识讲解。