python 线程(创建2种方式,锁,死锁,递归锁,GIL锁,守护进程)
###############总结############
线程创建的2种方式(重点)
进程:资源分配单位 线程:cpu执行单位(实体)
线程的创建和销毁的开销特别小
线程之间资源共享,是同一个进程中的资源共享,会涉及到安全问题,所以需要加锁解决
锁:牺牲了效率,保证了数据安全(重点)
死锁现象:出现在嵌套的时候,双方互相抢对方已经拿到的锁,导致双方互相等待(重点)
递归锁: 解决了死锁现象(重点)
rlock 首先本身就是个互斥锁,维护了一个计数器,每次acquire+1,release就-1,当计数器为0的时候,大家才会抢这个锁
守护线程:
守护线程:等待所有非守护线程结束才结束
守护进程: 主进程运行代码结束,守护进程会随之结束
GIL锁:
运行一个py文件 需要开辟一块内存,内存中有 cpython解释器,py文件代码
cpython解释器有 编译器和虚拟机 编译器:编译出来后是c语言的字节码
经过虚拟机后:变成可执行的二进制文件 到cpu里面执行
py文件代码到cpython解释器的时候,会经过一个gil锁,这个锁会把文件中的多个线程变成并行处理的方式
这样的话 一次只能出一个二进制文件导致单核cpu执行,没法做到多线程
如果做到同时处理多核计算形任务了?
使用多进程运用进程运用多核技术,因为每个进程里面都有cpython解释器程序
一个普通的cpu 一秒可以随便执行500万条mps 也就是5亿条指令
如果你的程序是I/O型的(一般你的程序都是这个)(input、访问网址网络延迟、打开/关闭文件读写),
在什么情况下用的到高并发呢(金融计算会用到,人工智能(阿尔法狗),但是一般的业务场景用不到,爬网页,多用户网站、聊天软件、处理文件)
I/O型的操作很少占用CPU
###第一种
from threading import Thread def f1(n): print(n) if __name__ == '__main__': t1=Thread(target=f1,args=(1,)) t1.start() ###第二种 class mythread(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): print('hellow'+self.name) if __name__ == '__main__': t=mythread('alex') t.start() print('主线程结束')
#####################
1
hellowalex
主线程结束
###查看线程的进程id
import os from threading import Thread def f1(n): print('1号',os.getpid()) print('%s号'%n) def f2(n): print('2号',os.getpid()) print('%s'%n) if __name__ == '__main__': t1=Thread(target=f1,args=(1,)) t2=Thread(target=f2,args=(2,)) t1.start() t2.start() print('主进程id',os.getpid()) ############ 线程ID是一样的
###验证线程是数据共享的
import os import time from threading import Thread num=100 def f1(n): global num num=3 print('子线程num',num) if __name__ == '__main__': t=Thread(target=f1,args=(1,)) t.start() t.join()#主进程等待子进程运行完才继续执行 print('主进程的num',num)
###################
子线程num 3
主进程的num 3
###多进程效率对比
import time from threading import Thread from multiprocessing import Process def f1(): for i in range(5): i=i+i if __name__ == '__main__': t_s_time=time.time() t_list=[] # 查看一下20个线程执行20个任务的执行时间 for i in range(20): t=Thread(target=f1,) t.start() t_list.append(t) [tt.join() for tt in t_list] t_e_time=time.time() t_dif_time=t_e_time-t_s_time # print(t_dif_time) #查看一个20个进程执行的任务时间 ########################################## p_s_time=time.time() p_list=[] for i in range(20): p=Process(target=f1,) p.start() p_list.append(p) [pp for pp in p_list] p_e_time=time.time() p_dif_time=p_e_time-p_s_time print('线程执行的时间%s'%t_dif_time) print('进程执行的时间%s' % p_dif_time) ################### 线程执行的时间0.003000497817993164 进程执行的时间0.2560145854949951
####锁 牺牲了效率,保证了数据安全(重点)
import time from multiprocessing import Process from threading import Thread,Lock num=100 def f1(loc): loc.acquire()#没加锁的时候 多个程序会抢一个数据 造成数据不安全 global num tmp=num tmp-=1 time.sleep(0.01)#模拟 num=tmp loc.release() if __name__ == '__main__': t_loc=Lock() t_list=[] for i in range(10): t=Thread(target=f1,args=(t_loc,)) t.start() t_list.append(t) [tt.join() for tt in t_list] print('主进程',num) ############## 主进程 90
#####死锁现象 出现在嵌套的时候,双方互相抢对方已经拿到的锁,导致双方互相等待(重点)
import time from threading import Thread,Lock,RLock def f1(locA,locB): locA.acquire() print('f1>>1号抢到了A锁') time.sleep(1) locB.acquire() print('f1>>1号抢到了B锁') locB.release() locA.release() def f2(locA,locB): locB.acquire() print('f2>>2号抢到了B锁') locA.acquire() time.sleep(1) print('f2>>2号抢到了A锁') locA.release() locB.release() if __name__ == '__main__': locA = Lock() locB = Lock() t1 = Thread(target=f1,args=(locA,locB)) t2 = Thread(target=f2,args=(locA,locB)) t1.start() t2.start() ################## f1>>1号抢到了A锁 f2>>2号抢到了B锁
递归锁: 解决了死锁现象(重点)
rlock 首先本身就是个互斥锁,维护了一个计数器,每次acquire+1,release就-1,当计数器为0的时候,大家才会抢这个锁
import time from threading import Thread,Lock,RLock def f1(LocA,LocB): # time.sleep(1) LocA.acquire() print('f1>>1号抢到a锁') time.sleep(1) LocB.acquire() print('f1>>1号抢到b锁') LocB.release() LocA.release() def f2(LocA, LocB): # time.sleep(1) LocB.acquire() print('f2>>2号抢到b锁') time.sleep(1) LocA.acquire() print('f2>>2号抢到a锁') LocA.release() LocB.release() if __name__ == '__main__': LockA=Lock() LockB=Lock() LockA=LockB=RLock()#递归锁,维护一个计时器,acquire+1 release-1 t1=Thread(target=f1,args=(LockA,LockB)) t2=Thread(target=f2,args=(LockA,LockB)) t1.start() t2.start() ####################### f1>>1号抢到a锁 f1>>1号抢到b锁 f2>>2号抢到b锁 f2>>2号抢到a锁
守护线程: 等待所有非守护线程结束才结束
import time from threading import Thread def f1(): time.sleep(3) print('xxxxxx') def f2(): time.sleep(2) print('普通子进程的代码') if __name__ == '__main__': p=Process(target=f1,) p.daemon=True # 等待所有非守护线程结束才结束 p.start() p2=Process(target=f2,) p2.start() p2.join() print('主进程,结束') #################### 普通子进程的代码 主进程,结束
如果把 上面的 f2 改成3s f1改成2s 会打印出xxxx 因为f2执行时间大于f1函数