Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量一丶线程的理论知识什么是线程:???1.线程是一堆指令,是操作系统调度的最小单位 ???2.线程具有执行能力 ????3.线程依赖于进程 ????4.具有主从关系(人为定义,每一个进程都至少有一个主线程 二丶开启线程的两种方式(Thread)类的方式开启线程### 利用到Thread from threading import Thread class MyThread(Thread): def run(self) -> None: # 必须重写run函数 print(f'{self.name} 被开启了~~') if __name__ == '__main__': t=MyThread() # 实例化一个自定义线程类对象 t.start() # 启动子线程 print('in 主线程') 函数的方式开启线程### 函数开启线程 from threading import Thread def task(name): print(f'在子线程中: {name}') if __name__ == '__main__': t=Thread(target=task,args=('abc',)) # 实例化线程对象 t.start() # 启动子线程 print('主~~~~') 三丶线程和进程之间的对比进程VS线程:???1.线程的启动速度 快于 进程的启动速度 ???2.线程之间数据可以共享,进程之间不能数据共享(必须依靠队列才能实现) ???3.线程开销小,进程开销大 ???4.在运行速度上,进程和线程是没有可比性.(两个不同的概念,线程具有执行能力,进程不具有执行能力) 四丶线程的其他方法两种:???1.线程对象方法 ???2.threading对象方法 # -*-coding:utf-8-*- # Author:Ds from threading import Thread import threading import time ### 定义开启子线的方法 def task(): time.sleep(1) # 睡1秒,保证所有的子线程都能存活1秒 以上 print(f'123') print(threading.current_thread().name) #子线程对象名字 if __name__ == '__main__': for i in range(6): t=Thread(target=task,name='firstIn') #target指定子线程任务,name子线程名 t.start() ### 1. 线程对象方法 print(t.isAlive()) # 判断线程是否还存活 t.setName('32141') # 设置name属性 print(t.getName()) # 获得线程名 ### 2 threading模块方法 print(threading.current_thread()) #线程对象 print(threading.enumerate()) # 列表 [<_MainThread(MainThread,started 10748)>,<Thread(firstIn,started 3696)>,] print(threading.active_count()) # 获取活跃的线程数量 (包括主线程 ) 7个 print('主线程') 五丶守护进程什么是守护线程:???1.守护线程必须等待所有的非守护线程以及主线程结束之后才结束 ???2.本质还是子线程,在开启前被设置成守护线程. ### 守护线程 from threading import Thread import time def task(name): print(f'{name} is running') time.sleep(1) # 当主线程结束了,当前守护线程也就结束了 print(f'{name} is over') if __name__ == '__main__': t = Thread(target=task,)) t.daemon = True # 将一个子线程设置为守护线程 t.start() print('主线程') 容易产生歧义:???1.首先 要明确,在同一时刻,CPU只允许一个任务的存在,遇到IO阻塞进行任务切换 ???2.守护进程VS守护线程 ??????守护线程:必须等待所有的非守护线程执行完毕以及主线程执行完毕,才能结束 ??????守护进程:守护进程不会等待所有的非守护进程完毕才结束.只要主进程GG,守护进程GG ### 守护线程: from threading import Thread import time def foo(): print(123) time.sleep(1) # sleep 表示要切换,执行bar子线程 print("end123") def bar(): print(456) # 执行 守护线程必须等待非守护线程执行完毕才能结束 time.sleep(3) print("end456") if __name__ == '__main__': t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon = True t1.start() t2.start() print("main-------") 六丶互斥锁含义:???1.互斥锁,同步锁,锁.都是同一种锁LOCK ???2.在并发时,保证数据的安全(‘串行‘) ###互斥锁 实现 '并发' # -*-coding:utf-8-*- # Author:Ds from threading import Thread from threading import Lock # 这是线程的 互斥锁 import time x=100 def task(lock): lock.acquire() # 加锁 实现 '并发',保证数据的安全性 global x temp = x time.sleep(0.1) temp -= 1 x = temp print(x) lock.release() if __name__ == '__main__': lock=Lock() # 实例化锁对象 #### 如果想要实现并发. 1.把所有的实例对象都添加列表中,2 join循环列表,每一个线程都必须等待上一个线程执行完,必须等待上一个线程执行完 t_li=[] # 存放线程对象,实现并发 for i in range(100): # 创建100个子线程 t=Thread(target=task,args=(lock,)) t_li.append(t) t.start() for el in t_li: el.join() # 循环列表,必须等待上一个线程执行完 print(f'最后x:{x}') 七丶死锁现象,递归锁死锁含义(Lock):???一个资源被多次调用,多次调用资源未能释放,会造成一种互相等待的现象.在没有外力作用下,只能停留在这,此时的系统处于锁死状态. 死锁现象(2种):???1.当一个进程或者一个线程一直占调用或者占用同一把锁Lock时,而不释放资源会导致其他进程/线程无法获得锁,就会出现锁死现象.一直出去阻塞acquire()状态 ??????代码见??: ### 当一个锁对象已经被上锁,试图再次加锁,就会造成锁死. from multiprocessing import Lock def task1(loc): print('task1') loc.acquire() print('task1: 开始打印') time.sleep(random.randint(1,3)) print('task1: 结束打印') loc.release() def task2(loc): print('task2') loc.acquire() # 第一层锁 loc.acquire() #第二层锁,由于锁对象已经被占用(已经锁上了,还没有释放)再次上锁,就会造成锁死 (程序被卡主)~~~ loc.release() print('task2: 开始打印') time.sleep(random.randint(1,3)) print('task2: 结束打印') loc.release() def task3(loc): print('task3') loc.acquire() print('task3: 开始打印') time.sleep(random.randint(1,3)) print('task3: 结束打印') loc.release() if __name__ == '__main__': loc=Lock() p1=Process(target=task1,args=(loc,)).start() p2=Process(target=task2,)).start() p3=Process(target=task3,)).start() ???2.当有两个进程/线程同时想要获取两个锁时,由于两者都是处于竞争关系.就可能会出现两者都阻塞在同一放,都无法同时获得两个锁 或者 要获取对方已经获得的还没有释放的锁. # -*-coding:utf-8-*- # Author:Ds from threading import Thread from threading import Lock import time # 两把 不一样的锁 lock_A=Lock() lock_B=Lock() class MyThread(Thread): def run(self) -> None: self.f1() self.f2() def f1(self): lock_A.acquire() print(f'{self.name} 拿到A锁') lock_B.acquire() # print(f'{self.name} 那到B锁') lock_B.release() lock_A.release() def f2(self): lock_B.acquire() print(f'{self.name} 拿到B锁') time.sleep(1) lock_A.acquire() print(f'{self.name} 拿到A锁') lock_A.release() lock_B.release() if __name__ == '__main__': for i in range(2): # 实例化两个线程对象 t=MyThread() # 简单命名,线程1和线程2 t.start() print('in 主线程') ### 口述上述代码的过程: #1. 线程 1 执行f1函数,拿到A锁,线程2 也要拿A锁. 由于线程1已经拿到A锁,线程2必须等待A锁 #2. 线程1 继续执行f1函数,此时 B锁没有人使用. 轻松的执行完 f1函数 #3. 重点: 线程1执行f2函数 拿走B锁. 而此时A锁已经被释放了,现在线程2拿走A锁,#4. 重点: 线程1执行f2函数 已经拿走B锁,继续执行需要A锁. 此时发现A锁已经被线程2拿走了,线程2 执行f1函数,已经拿走了A锁,需要B锁.而此时B锁在线程1中. ### 由于竞争关系的存在. 两个线程对同一个资源进行抢夺. 一直卡在acquire(),造成死锁. ? 递归锁(RLock):???1.防止线程锁死 ???2.引用计数原则:非0不能被抢,引用1次锁一次,引用N次锁N次. ???3.在并发时,保证数据的安全(‘串行‘) # -*-coding:utf-8-*- # Author:Ds ### 递归锁是一把锁,锁上有记录,只要acquire一次,锁上就计数1次,acquire2次,锁上就计数2次,# release1次,减一,# 只要递归锁计数不为0,其他线程不能抢. from threading import Thread from threading import RLock import time # 同一个锁对象,两把一样的锁,内部采用单例模式 lock_A=lock_B=RLock() class MyThread(Thread): def run(self) -> None: self.f1() self.f2() def f1(self): lock_A.acquire() print(f'{self.name} 拿到A锁') lock_B.acquire() # print(f'{self.name} 那到B锁') lock_B.release() lock_A.release() def f2(self): lock_B.acquire() print(f'{self.name} 拿到B锁') time.sleep(1) lock_A.acquire() print(f'{self.name} 拿到A锁') lock_A.release() lock_B.release() if __name__ == '__main__': for i in range(2): # 实例化两个线程对象 t=MyThread() t.start() print('in 主线程') 八丶信号量含义:???信号量允许多个线程或者进程同时进入 描述:???描述:一个网吧,有三台电脑,一开始三台电脑都没有人.这时候来了5个人要上网,网管允许3个人进入网吧,使用电脑. 剩下的2个人就必须在门外等待,此后来的认也要在门外等待. 如果这时候有1个人已经上完网了,网管得知后,打开网吧的门,让后面的1个人进入网吧上网.如果这时候又有2个人已经上网完毕离开了,网管又打开门,让后面的2个人进入网吧上网. ???在网吧系统中,上网电脑: 属于公共资源,上网的人属于一个线程,网管就是起着信号量的作用 # -*-coding:utf-8-*- # Author:Ds ### 信号量: 同一时间,只允许指定数量的线程工作.(多余的线程排队等候) ### 信号量允许多个线程或者进程同时进入 from threading import Thread from threading import current_thread from threading import Semaphore import time import random sm=Semaphore(3) # 定义信号量对象 同一时刻只允许3个任务被处理 def Safe_Internet(): sm.acquire() print(f'{current_thread().name} 正在上网') time.sleep(random.randint(1,3)) # 增加随机性 sm.release() print(f' 33[0;35m {current_thread().name} 已经上完网了 33[0m') if __name__ == '__main__': t_l=[] for i in range(20): t=Thread(target=Safe_Internet,) t_l.append(t) t.start() for i in t_l: i.join() print('in 主线程~~~~') (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |