GIL锁
GIL锁引入
- 监控资源的竞争情况 htop
- 资源的消耗的情况
- 单进程 1核
- 多进程 多核
- 多线程 多核但是很低 gil锁的问题
# 单进程、单线程死循环
def test():
while True:
pass
test()
# 多进程
import multiprocessing
def deadLoop():
while True:
pass
# 子进程死循环 进程2
p1 = multiprocessing.Process(target=deadLoop)
p1.start()
# 主进程死循环 进程1
deadLoop()
# 多线程
import threading
# 子线程死循环
def test():
while True:
pass
t1 = threading.Thread(target=test)
t1.start()
# 主线程死循环
while True:
pass
GIL概念及影响
- Gil 全局解释器锁
- GIL跟python语言没有关系,Python底层解释器Cpython的问题
- GIL释放的情况
- 线程执行完毕释放
- I/O 阻塞的时候释放
- Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)
GIL解决方案
- 解决方案:
- 更换解释器 Jpython pypy(不推荐)
- 用进程替换线程(进程会占用更多的系统资源)(推荐)
- 子线程用C语言实现(test.c-->libtest.so-->python加载)(推荐)
- 使⽤python语⾔的特性:胶⽔.
- 我们让⼦线程部分⽤c来写,就ok。(实质上也相当于那部分代码绕过了cython解释器)
- gcc test.c -shared -o libtest.so
- -shared:将其编译成so⽂件
- -o:表示output,⽤来输出的⽂件名
- 库⽂件是以lib开头
- 编译过后,在当前的⽂件夹下就会⽣成⼀个.so⽂件
# # test.c
# void Loop()
# {
# while(1)
# {
# ;
# }
# }
# gcc test.c -shared -o libtest.so
# 1、导入模块ctypes
import ctypes
import threading
# 2、加载so文件
mylib = ctypes.cdll.LoadLibrary("./libtest.so")
# 3、创建子线程,并且启动
t1 = threading.Thread(target=mylib.Loop)
t1.start()
# 4、主线程死循环
while True:
pass
python中可变和不可变类型
可变不可变,是指内存中那块内容(value)是否可以被改变
- 可变类型(mutable),创建后可以继续修改对象的内容(值)
- 字典、列表
- 不可变类型(unmutable) ,一旦创建就不可修改的对象(值)
- 数字, 字符串,元组
- 当内容发生修改,计算机重新分配一块内存空间
"""
可变: 变量创建完成后,内存内容可以在改变
不可变: 变量创建,内存空间一旦分配完成,就不能在改变了
"""
# a 变量,保存数字,不可变的
a = 5
print("a =", a, id(a))
# 修改变量值
# 重新开辟一块内存空间存放a的值
a = 5 + 1
print("a =", a, id(a))
list1 = [1, 3, 5]
print("list1 =", list1, id(list1))
# 给列表增加新的元素
list1.append(7)
print("list1 =", list1, id(list1))
# list1赋值给list2
list2 = list1
list2.append(9)
print("list2 =", list2, id(list2))
a = 5 140703238994488
a = 6 140703238994520
list1 = [1, 3, 5] 2135961382336
list1 = [1, 3, 5, 7] 2135961382336
list2 = [1, 3, 5, 7, 9] 2135961382336
简单可变类型拷贝
import copy
深拷贝与浅拷贝区别:
- 深拷贝:copy.deepcopy(变量名)
- 会产生新的空间
- 能够保持各自的独立性
- 如果拷贝的是对象,子对象也会拷贝(产生新的空间)
- 浅拷贝:copy.copy(变量名)
- 不会产生新的空间
- 源对象和副本对象指向同一个空间
- 如果拷贝的是对象,子对象不会拷贝(不会产生新的空间)
简单可变类型的拷贝总结:简单可变类型的数据不管深拷贝还是浅拷贝,都会产生新的空间,而且保持各自的独立性
import copy
list1 = [1, 3, 5, 7]
print("list1 =", list1, id(list1))
list2 = list1
print("list2 =", list2, id(list2))
list2.append(9)
print("list2 =", list2, id(list2))
# 浅拷贝
list3 = copy.copy(list1)
print("list3 =", list3, id(list3))
print("---------------------------------")
list1.append(11)
list2.append(13)
print("list1 =", list1, id(list1))
print("list2 =", list2, id(list2))
print("list3 =", list3, id(list3))
# 深拷贝
list4 = copy.deepcopy(list1)
print("list4 =", list4, id(list4))
list1.append(15)
print("---------------------------------")
print("list1 =", list1, id(list1))
print("list2 =", list2, id(list2))
print("list3 =", list3, id(list3))
print("list4 =", list4, id(list4))
list1 = [1, 3, 5, 7] 1725240142464
list2 = [1, 3, 5, 7] 1725240142464
list2 = [1, 3, 5, 7, 9] 1725240142464
list3 = [1, 3, 5, 7, 9] 1725240257152 |
---|
list1 = [1, 3, 5, 7, 9, 11, 13] 1725240142464 |
list2 = [1, 3, 5, 7, 9, 11, 13] 1725240142464 |
list3 = [1, 3, 5, 7, 9] 1725240257152 |
list4 = [1, 3, 5, 7, 9, 11, 13] 1725239723136 |
--------------------------------- |
list1 = [1, 3, 5, 7, 9, 11, 13, 15] 1725240142464 |
list2 = [1, 3, 5, 7, 9, 11, 13, 15] 1725240142464 |
list3 = [1, 3, 5, 7, 9] 1725240257152 |
list4 = [1, 3, 5, 7, 9, 11, 13] 1725239723136 |
复杂可变类型拷贝
复杂可变类型的深浅拷贝问题
- 浅拷贝,拷贝的是顶层对象的值,子对象不会拷贝(只是引用子对象)
- 深拷贝,拷贝的顶层对象和对象的子对象,子对象会产生新的内存空间
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
print("a的地址:", id(a))
print("b的地址:", id(b))
print("c的地址:", id(c))
print("c[0]的地址:", id(c[0]))
print("c[1]的地址:", id(c[1]))
print("--" * 20)
# 浅拷贝
d = copy.copy(c)
a[0] = 10
b[0] = 40
print("d的地址:", id(d))
print("d[0]的地址:", id(d[0]), d[0])
print("d[1]的地址:", id(d[1]), d[1])
print("--" * 20)
# 深拷贝
e = copy.deepcopy(c)
a[0] = 100
b[0] = 400
print("e的地址:", id(e))
print("e[0]的地址:", id(e[0]), e[0])
print("e[1]的地址:", id(e[1]), e[1])
a的地址: 1725246712000
b的地址: 1725246708032
c的地址: 1725246711104
c[0]的地址: 1725246712000
c[1]的地址: 1725246708032 |
---|
d的地址: 1725246701824 |
d[0]的地址: 1725246712000 [10, 2, 3] |
d[1]的地址: 1725246708032 [40, 5, 6] |
---------------------------------------- |
e的地址: 1725246640960 |
e[0]的地址: 1725246712128 [10, 2, 3] |
e[1]的地址: 1725246716096 [40, 5, 6] |
简单不可变类型拷贝
- copy() 浅拷贝,副本和源指向同一个空间
- deepcopy() 深拷贝,副本和源指向同一个空间
import copy
str = "helloworld"
tpl = (1, 2, 3)
print("str =", str, id(str))
print("tpl =",tpl, id(tpl))
# 浅拷贝
str2 = copy.copy(str)
tpl2 = copy.copy(tpl)
print("str2 =", str2, id(str2))
print("tpl2 =",tpl2, id(tpl2))
print("--" * 20)
# 深拷贝
str3 = copy.deepcopy(str)
tpl3 = copy.deepcopy(tpl)
print("str3 =", str3, id(str3))
print("tpl3 =",tpl3, id(tpl3))
str = helloworld 1725239643952
tpl = (1, 2, 3) 1725246702848
str2 = helloworld 1725239643952
tpl2 = (1, 2, 3) 1725246702848 |
---|
str3 = helloworld 1725239643952 |
tpl3 = (1, 2, 3) 1725246702848 |
复杂不可变类型拷贝
复杂不可变类型的拷贝问题
- 浅拷贝,直接引用
- 深拷贝,看数据具体是可变还是不可变的,如果数据是可变的,会产生新的空间,保持数据的独立性
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = (a, b)
print("a的地址:",a, id(a))
print("b的地址:",b, id(b))
print("c的地址:",c, id(c))
print("c[0]的地址:",c[0], id(c[0]))
print("c[1]的地址:",c[1], id(c[1]))
print("--" * 20)
# 浅拷贝
d = copy.copy(c)
c[0][0] = 10
c[1][0] = 40
print("a的地址:",a, id(a))
print("b的地址:",b, id(b))
print("c的地址:",c, id(c))
print("c[0]的地址:",c[0], id(c[0]))
print("c[1]的地址:",c[1], id(c[1]))
print("d[0]的地址:",d[0], id(d[0]))
print("d[1]的地址:",d[1], id(d[1]))
print("--" * 20)
# 深拷贝
e = copy.deepcopy(c)
c[0][0] = 100
c[1][0] = 400
print("a的地址:",a, id(a))
print("b的地址:",b, id(b))
print("c的地址:",c, id(c))
print("c[0]的地址:",c[0], id(c[0]))
print("c[1]的地址:",c[1], id(c[1]))
print("e[0]的地址:",e[0], id(e[0]))
print("e[1]的地址:",e[1], id(e[1]))
a的地址: [1, 2, 3] 1725246733120
b的地址: [4, 5, 6] 1725246834112
c的地址: ([1, 2, 3], [4, 5, 6]) 1725240756544
c[0]的地址: [1, 2, 3] 1725246733120
c[1]的地址: [4, 5, 6] 1725246834112 |
---|
a的地址: [10, 2, 3] 1725246733120 |
b的地址: [40, 5, 6] 1725246834112 |
c的地址: ([10, 2, 3], [40, 5, 6]) 1725240756544 |
c[0]的地址: [10, 2, 3] 1725246733120 |
c[1]的地址: [40, 5, 6] 1725246834112 |
d[0]的地址: [10, 2, 3] 1725246733120 |
d[1]的地址: [40, 5, 6] 1725246834112 |
---------------------------------------- |
a的地址: [100, 2, 3] 1725246733120 |
b的地址: [400, 5, 6] 1725246834112 |
c的地址: ([100, 2, 3], [400, 5, 6]) 1725240756544 |
c[0]的地址: [100, 2, 3] 1725246733120 |
c[1]的地址: [400, 5, 6] 1725246834112 |
e[0]的地址: [10, 2, 3] 1725246834048 |
e[1]的地址: [40, 5, 6] 1725246832704 |
切片拷贝、字典拷贝
- 切片拷贝: 浅拷贝(如果是简单可变类型,底层会产生新的空间)
- 字典拷贝: 浅拷贝
深拷贝和浅拷贝总结:
- 拷贝简单可变的数据类型的时候 a = []
- 深拷贝和浅拷贝是一样的 都会开辟新的空间存储数据 可以保证数据的独立性
- 拷贝有嵌套的复杂的数据类型 a = [[],[]]
- 浅拷贝 开辟一片空间 存放拷贝对象的地址 没办法保证数据的独立性
- 深拷贝 开辟多片空间 存放拷贝对象的具体数据和地址 保证数据的独立性
- 拷贝不可变的数据类型()
- 深拷贝和浅拷贝都一样 都不会开辟新的空间 而是直接引用了被拷贝的数据的地址
- 拷贝不可变的数据类型中嵌套了可变数据类型
- 浅拷贝:只关心最外的数据类型是什么 如果是不可变的数据类型 直接引用 没有办法保证数据的独立性
- 深拷贝:这个数据是否有可变的数据类型 如果有它就会开辟多个空间存储数据和地址 达到保证数据独立性的作用
- 切片拷贝,字典拷贝
- 在python中多数情况下都是浅拷贝
import copy
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 简单数据类型,切片拷贝
list2 = list[:]
print("list =", list, id(list))
print("list2 =", list2, id(list2))
print("--" * 20)
# 复杂数据类型,切片拷贝
a = [1, 2, 3]
b = [4, 5, 6]
c = (a, b)
print("a的地址:",a, id(a))
print("b的地址:",b, id(b))
print("c的地址:",c, id(c))
print("c[0]的地址:",c[0], id(c[0]))
print("c[1]的地址:",c[1], id(c[1]))
print("--" * 20)
d = c[:]
print("d的地址:",d, id(d))
print("d[0]的地址:",d[0], id(d[0]))
print("d[1]的地址:",d[1], id(d[1]))
print("--" * 20)
# 字典拷贝
dict = {"age": [1, 8]}
print("dict =", dict, id(id))
dict2 = dict.copy()
dict["age"][1] = 100
print("dict =", dict, id(id))
print("dict2 =", dict2, id(id))
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1725247214144
list2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1725247210496 |
---|
a的地址: [1, 2, 3] 1725240354624 |
b的地址: [4, 5, 6] 1725247212224 |
c的地址: ([1, 2, 3], [4, 5, 6]) 1725247100416 |
c[0]的地址: [1, 2, 3] 1725240354624 |
c[1]的地址: [4, 5, 6] 1725247212224 |
---------------------------------------- |
d的地址: ([1, 2, 3], [4, 5, 6]) 1725247100416 |
d[0]的地址: [1, 2, 3] 1725240354624 |
d[1]的地址: [4, 5, 6] 1725247212224 |
---------------------------------------- |
dict = {'age': [1, 8]} 1725149307392 |
dict = {'age': [1, 100]} 1725149307392 |
dict2 = {'age': [1, 100]} 1725149307392 |