GIL 相关 和进程池

时间:2023-07-09 22:20:08
#GIL  (global interpreter Lock)

#全局解释器锁 :锁是为了避免资源竞争造成数据错乱

#当一个py启动后 会先执行主线程中的代码
#在以上代码中有启动了子线程 子线程的任务还是执行代码
#解释器在一个进程中只有一个(解释器也是一堆代码)
#主线和子线都要去调用解释器,就存在了竞争关系 #全局解释器锁: 是为了防止多个线程同时使用python解释器 一旦加锁 将导致线程无法并行
#这个问题不是所有解释器都存在 只有cpython(c写的解释器) 也就是说只有cpythonzhong
#有全局解释器锁 如果是Jpython 就要参考Java的多线程实现
#python程序的执行:
#1.启动解释器进程 python.exe
#2.解析py文件并执行它 # 每个py程序中都必须有解释器参与 解释器其实就是一堆代码
#相当于多个线程要调用同一个解释器代码 共享变成竞争 竞争就要出事 给解释器加互斥锁 # python中内存管理依赖于GC(一段用于回收内存的代码) 也需要一个线程 除了自己开的线
# 程 系统还有一些内置线程 就算你的代码不会去竞争解释器 内置线程也可能会竞争 所以
# 所以必须加上锁 #当一个线程遇到了IO 同时解释器也会自动解锁 去执行其他线程 cpu会切换到其他程序
# 案例:
# from threading import Thread
# import time
# def task1():
# sum=1
# for i in range(10000000):
# sum+=i
# def task2():
# sum=1
# for i in range(10000000):
# sum+=i
# start=time.time()
# t1=Thread(target=task1)
# t2=Thread(target=task2)
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(time.time()-start) #解释器加锁以后:
#将导致所有线程只能并发 不能达到真正的并行 意味着同意时间只有一个cpu在处理你的
#线程 给你的感觉是小路低 #代码执行有两种状态;
#阻塞 i/o :失去cpu的执行权 (cpu等待I/O完成)
#非阻塞 :代码正常执行 比如循环一千万次 中途cpu可能切换 但是很快会回来(cpu在计算) #加入有32核cpu 要处理一个下载任务 网络速度慢 100k/s 文件大小为1024kb 如果你的代码中
#IO操作非常多 cpu性能不能直接决定你的任务处理速度 #案例:
#目前有三个任务 每个任务处理需要一秒 获取元数据需要一小时
#3个cpu 需要一小时一秒
#1个cpu 需要一小时三秒 #在IO密集的程序中 cpu性能无法直接决定程序的执行速度 python就应该干这种活儿
#在计算密集的程序中 cpu性能可以直接决定程序的执行效率 #2.GIL与互斥锁
#GIL与互斥锁:
# from threading import Thread,Lock
# import time
# mutex=Lock()
# num = 1
# def task():
# global num
# mutex.acquire()
# temp=num
# time.sleep(1) #当线程中出现io时 GIL锁就解开了
# num=temp+1
# mutex.release()
# t1=Thread(target=task,)
# t2=Thread(target=task,)
# t1.start()
# t2.start()
# t1.join()
# t2.join()
# print(num)
# #GIL和自定义互斥锁的区别
# #全局锁不能保证自己的线程安全 但是保证解释器中的数据安全
# #GIL在线程调用解释器时 自动加锁 IO阻塞时和线程代码执行完毕时 自动解锁
#
#3.线程池与进程池
# 进程池: 就是一个装进程的容器
# 为什么出现: 当进程很多的时候方便管理进程
# 什么时候用:当并发量特别大的时候 例如双十一 很多时候进程是空闲的 就让他进入进程池
#让有任务处理的进程进入进程池
# 进程池:
# ProcessPoolExecutor
# 创建时指定最大进程数 自动创建进程
# 调用submit函数将任务提交到进程池中
# 创建进程是在调用submit后发生的
#举例:
# #收发数据
# def task(c,addr):
# while True:
# data=c.recv(1024)
# print(data.decode("utf-8"))
# if not data:
# c.close()
# break
# c.send(data.upper())
# if __name__ == '__main__':
# import socket
# from concurrent.futures import ProcessPoolExecutor
# server=socket.socket()
# server.bind(("127.0.0.1",8091))
# server.listen(5)
# #创建一个进程池 默认
# pool=ProcessPoolExecutor()
# while True:
# c,addr = server.accept()
# pool.submit(task,c,addr) #总结一下:
# 进程池可以自动创建进程
# 进程限制最大进程数
# 自动选择一个空闲的进程帮你处理任务