第一阶段:Python开发基础 day39 多线程的进阶补充内容
发布时间:2020-12-20 10:41:24 所属栏目:Python 来源:网络整理
导读:目录 昨日回顾 一、线程锁 二、死锁问题 三、递归锁(了解) 四、信号量 五、GIL 六、多进程vs多线程 昨日回顾 '''cpu最小的执行单位:线程进程 资源集合线程 执行单位操作系统 -- 工厂进程 -- 车间线程(cpu)-- 流水线(电源)进程的内存空间彼此隔离线程共享同
目录
昨日回顾''' cpu最小的执行单位:线程 进程 资源集合 线程 执行单位 操作系统 --> 工厂 进程 --> 车间 线程(cpu)--> 流水线(电源) 进程的内存空间彼此隔离 线程共享同一份资源 ''' ### 方式一 # from threading import Thread # # def task(): # pass # # # if __name__ == '__main__': # t = Thread(target= task) # t.start() ### 方式二 类 # pass #### 创建速度 # 进程需要申请内存空间 慢 # 线程相当于直接告诉操作系统去干个什么活. 快 ### 线程共享资源 ### 线程的join方法: 等待被join的线程结束 # 进程的join:等待被join的进程结束 ### 线程其他的相关用法: getname setname enumerate() currentThread ### 守护线程: 守护的是进程运行周期 一、线程锁from threading import Thread,Lock x = 0 mutex = Lock() def task(): global x # mutex.acquire() for i in range(200000): x = x+1 # t1 的 x刚拿到0 保存状态 就被切了 # t2 的 x拿到0 进行+1 1 # t1 又获得运行了 x = 0 +1 1 # 思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1 # 这就产生了数据安全问题. # mutex.release() if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t3 = Thread(target=task) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() print(x) 二、死锁问题from threading import Thread,Lock mutex1 = Lock() mutex2 = Lock() import time class MyThreada(Thread): def run(self): self.task1() self.task2() def task1(self): mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') def task2(self): mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') time.sleep(1) mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') for i in range(3): t = MyThreada() t.start() # 两个线程 # 线程1拿到了(锁头2)想要往下执行需要(锁头1),# 线程2拿到了(锁头1)想要往下执行需要(锁头2) # 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头. 三、递归锁(了解)from threading import Thread,Lock,RLock # 递归锁 在同一个线程内可以被多次acquire # 如何释放 内部相当于维护了一个计数器 也就是说同一个线程 acquire了几次就要release几次 # mutex1 = Lock() # mutex2 = Lock() mutex1 = RLock() mutex2 = mutex1 import time class MyThreada(Thread): def run(self): self.task1() self.task2() def task1(self): mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') def task2(self): mutex2.acquire() print(f'{self.name} 抢到了 锁2 ') time.sleep(1) mutex1.acquire() print(f'{self.name} 抢到了 锁1 ') mutex1.release() print(f'{self.name} 释放了 锁1 ') mutex2.release() print(f'{self.name} 释放了 锁2 ') for i in range(3): t = MyThreada() t.start() 四、信号量from threading import Thread,currentThread,Semaphore import time def task(): sm.acquire() print(f'{currentThread().name} 在执行') time.sleep(3) sm.release() sm = Semaphore(5) for i in range(15): t = Thread(target=task) t.start() 五、GIL# 在Cpython解释器中有一把GIL锁(全局解释器锁),GIl锁本质是一把互斥锁。 # 导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势. # 同一个进程下多个线程只能实现并发不能实现并行. # 为什么要有GIL? # 因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁. # 导致了同一个进程下,无法利用多核优势. # #分析: # 我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是: # 方案一:开启四个进程 # 方案二:一个进程下,开启四个线程 # 计算密集型 推荐使用多进程 # 每个都要计算10s # 多线程 # 在同一时刻只有一个线程会被执行,也就意味着每个10s都不能省,分开每个都要计算10s,共40.ns # 多进程 # 可以并行的执行多个线程,10s+开启进程的时间 # io密集型 推荐多线程 # 4个任务每个任务90%大部分时间都在io. # 每个任务io10s 0.5s # 多线程 # 可以实现并发,每个线程io的时间不咋占用cpu,10s + 4个任务的计算时间 # 多进程 # 可以实现并行,10s+1个任务执行的时间+开进程的时间 六、多进程vs多线程from threading import Thread from multiprocessing import Process import time # 计算密集型 # def work1(): # res=0 # for i in range(100000000): #1+8个0 # res*=i # # if __name__ == '__main__': # t_list = [] # start = time.time() # for i in range(4): # # t = Thread(target=work1) # t = Process(target=work1) # t_list.append(t) # t.start() # for t in t_list: # t.join() # end = time.time() # # print('多线程',end-start) # 多线程 15.413789510726929 # print('多进程',end-start) # 多进程 4.711405515670776 # # io密集型 # def work1(): # x = 1+1 # time.sleep(5) # # # if __name__ == '__main__': # t_list = [] # start = time.time() # for i in range(4): # t = Thread(target=work1) # # t = Process(target=work1) # t_list.append(t) # t.start() # for t in t_list: # t.join() # end = time.time() # print('多线程',end-start) # 多线程 5.002625942230225 # # print('多进程',end-start) # 多进程 5.660863399505615 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |