Python中的多线程
1、什么是线程
进程其实不是一个执行单位,进程是一个资源单位
每个进程内自带一个线程,线程才是CPU上的执行单位
如果把操作系统比喻为一座工厂
在工厂内每造出一个车间===》启动一个进程
每个车间内至少有一条流水线===》每个进程内至少有一个线程
线程==》单指代码的执行过程
进程==》资源的申请与销毁的过程
2、进程VS线程
1)内存共享or隔离
多个进程内存空间彼此隔离
同一进程下的多个线程共享该进程内的数据
2)创建速度
造线程的速度要远远快于造进程
一、开启线程的两种方式(重点)
方式一:导入Thread模块
1 from threading import Thread 2 import time 3 5 def task(name): 6 print('%s is running' %name) 7 time.sleep(3) 8 print('%s is done' %name) 9 if __name__ == '__main__': 10 t=Thread(target=task,args=('子线程',)) 11 t.start() 12 print('主')
方式二:创建类继承Thread
1 from threading import Thread 2 import time 3 4 6 # class Mythread(Thread): 7 # def run(self): 8 # print('%s is running' %self.name) 9 # time.sleep(3) 10 # print('%s is done' %self.name) 11 # 12 # if __name__ == '__main__': 13 # t=Mythread() 14 # t.start() 15 # print('主')
二、线程VS进程(重点)
1 # from threading import Thread 2 # from multiprocessing import Process 3 # import time 4 # 5 # def task(name): 6 # print('%s is running' %name) 7 # time.sleep(3) 8 # print('%s is done' %name) 9 # 10 # if __name__ == '__main__': 11 # t=Thread(target=task,args=('子线程',)) 12 # # t=Process(target=task,args=('子进程',)) 13 # t.start() 14 # print('主')
线程运行结果:
进程运行结果:
2)同一进程下的多个线程共享该进程内的数据(了解知识点)
1 # from threading import Thread 2 # import time 3 # 4 # x=100 5 # def task(): 6 # global x 7 # x=0 8 # 9 # if __name__ == '__main__': 10 # t=Thread(target=task,) 11 # t.start() 12 # # time.sleep(3) 13 # t.join() 14 # print('主',x)
3)查看pid(了解知识点)
注意:一个进程中的子线程pid相同
1 from threading import Thread 2 import time,os 3 4 def task(): 5 print(os.getpid()) 6 7 if __name__ == '__main__': 8 t=Thread(target=task,) 9 t.start() 10 print('主',os.getpid())
三、线程对象的其他方法和属性(熟悉知识点)
1)主进程等子进程是因为主进程要给子进程收尸
2)进程必须等待其内部所有线程都运行完毕才结束
1 # from threading import Thread 2 # import time 3 # 4 # def task(name): 5 # print('%s is running' %name) 6 # time.sleep(3) 7 # print('%s is done' %name) 8 # if __name__ == '__main__': 9 # t=Thread(target=task,args=('子线程',)) 10 # t.start() 11 # print('主') 12 #
1 from threading import Thread,current_thread,active_count,enumerate 2 import time 3 4 5 def task(): 6 print('%s is running' % current_thread().name) 7 time.sleep(3) 8 print('%s is done' % current_thread().name) 9 10 11 if __name__ == '__main__': 12 t = Thread(target=task,name='xxx') 13 t.start() 14 # t.join() 15 # print(t.is_alive()) 16 # print(t.getName()) 17 # print(t.name) 18 # print('主',active_count()) 19 # print(enumerate()) 20 21 # t.join() 22 current_thread().setName('主线程') 23 print('主',current_thread().name)
四、守护线程(熟悉知识点)
守护线程(daemon)会在本进程内所有非守护的线程都死掉了才跟着死
即:
守护线程其实守护的是整个进程的运行周期(进程内所有的非守护线程都运行完毕)
1 # from threading import Thread,current_thread 2 # import time 3 # 4 # 5 # def task(): 6 # print('%s is running' % current_thread().name) 7 # time.sleep(3) 8 # print('%s is done' % current_thread().name) 9 # 10 # 11 # if __name__ == '__main__': 12 # t = Thread(target=task,name='守护线程') 13 # t.daemon=True 14 # t.start() 15 # print('主')
1 from threading import Thread 2 import time 3 def foo(): 4 print(123) 5 time.sleep(3) 6 print("end123") 7 8 def bar(): 9 print(456) 10 time.sleep(1) 11 print("end456") 12 13 14 t1=Thread(target=foo) 15 t2=Thread(target=bar) 16 17 t1.daemon=True 18 t1.start() 19 t2.start() 20 print("main-------") 21 22 ''' 23 123 24 456 25 main------- 26 end456 27 28 '''
五、互斥锁(熟悉知识点)
1 from threading import Thread,Lock 2 import time 3 4 mutex=Lock() 5 6 x=100 7 def task(): 8 global x 9 # mutex.acquire() 10 temp=x 11 time.sleep(0.1) 12 x=temp-1 13 # mutex.release() 14 15 if __name__ == '__main__': 16 t_l=[] 17 start=time.time() 18 for i in range(100): 19 t=Thread(target=task) 20 t_l.append(t) 21 t.start() 22 23 for t in t_l: 24 t.join() 25 26 stop=time.time() 27 print(x,stop-start)
六、死锁现象与递归锁(熟悉知识点)
如果用Lock(互斥锁),会发生死锁现象
递归锁本质是一把锁,可连续acqruie,但只有其上的计数为0时其他线程才可对其调用
1 from threading import Thread,Lock,active_count,RLock 2 import time 3 4 # mutexA=Lock() 5 # mutexB=Lock() 6 obj=RLock() #递归锁的特点:可以连续的acquire 7 mutexA=obj 8 mutexB=obj 9 10 class Mythread(Thread): 11 def run(self): 12 self.f1() 13 self.f2() 14 15 def f1(self): 16 mutexA.acquire() 17 print('%s 拿到A锁' %self.name) 18 19 mutexB.acquire() 20 print('%s 拿到B锁' %self.name) 21 mutexB.release() 22 23 mutexA.release() 24 25 def f2(self): 26 mutexB.acquire() 27 print('%s 拿到B锁' %self.name) 28 time.sleep(1) 29 30 mutexA.acquire() 31 print('%s 拿到A锁' %self.name) 32 mutexA.release() 33 34 mutexB.release() 35 36 if __name__ == '__main__': 37 for i in range(10): 38 t=Mythread() 39 t.start() 40 # print(active_count())
七、信号量(熟悉知识点)
信号量本质上还是锁,但区别信号量是控制同一时刻并发执行的任务数
1 from threading import Thread,Semaphore,current_thread 2 import time,random 3 4 sm=Semaphore(5) 5 6 def task(): 7 with sm: 8 print('%s 正在上厕所' %current_thread().name) 9 time.sleep(random.randint(1,4)) 10 11 12 if __name__ == '__main__': 13 for i in range(20): 14 t=Thread(target=task) 15 t.start()