死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量
Posted xiejintao0914
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量相关的知识,希望对你有一定的参考价值。
死锁现象与解决方案
from threading import Thread,Lock,active_count import time mutexA=Lock() # 锁1 mutexB=Lock() # 锁2 class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print(‘%s 拿到A锁‘ %self.name) mutexB.acquire() print(‘%s 拿到B锁‘ %self.name) mutexB.release() mutexA.release() def f2(self): mutexB.acquire() print(‘%s 拿到B锁‘ %self.name) time.sleep(1) mutexA.acquire() print(‘%s 拿到A锁‘ %self.name) mutexA.release() mutexB.release() if __name__ == ‘__main__‘: for i in range(10): t=Mythread() t.start() # print(active_count()) #死锁现象: 线程1拿到一把锁,线程2也拿到一把锁,线程1想要线程2的锁,线程2想要线程1的锁,于是就阻塞了,这说明 2把锁不能同时acquire # 解决方法如下,递归锁 from threading import Thread,Lock,active_count,RLock import time # mutexA=Lock() # mutexB=Lock() obj=RLock() #递归锁的特点:可以连续的acquire.其本质其实还是一把锁,只是把一把锁转换成了2把而已 mutexA=obj mutexB=obj class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print(‘%s 拿到A锁‘ %self.name) mutexB.acquire() print(‘%s 拿到B锁‘ %self.name) mutexB.release() mutexA.release() def f2(self): mutexB.acquire() print(‘%s 拿到B锁‘ %self.name) time.sleep(1) mutexA.acquire() print(‘%s 拿到A锁‘ %self.name) mutexA.release() mutexB.release() if __name__ == ‘__main__‘: for i in range(10): t=Mythread() t.start() # print(active_count())
开启线程的2种方式
from threading import Thread import time #方式一 def task(name): print(‘%s is running‘ %name) time.sleep(3) print(‘%s is done‘ %name) if __name__ == ‘__main__‘: t=Thread(target=task,args=(‘子线程‘,)) t.start() print(‘主‘) #开启并发线程比开启并发进程要快的多,线程是在进程里开启,而进程是向操作系统发请求开辟一个新的内存空间 #方式二 # class Mythread(Thread): # def run(self): # print(‘%s is running‘ %self.name) # time.sleep(3) # print(‘%s is done‘ %self.name) # # if __name__ == ‘__main__‘: # t=Mythread() # t.start() # print(‘主‘)
01 什么是线程 进程其实不是一个执行单位,进程是一个资源单位 每个进程内自带一个线程,线程才是cpu上的执行单位 如果把操作系统比喻为一座工厂 在工厂内每造出一个车间===》启动一个进程 每个车间内至少有一条流水线===》每个进程内至少有一个线程 线程=》单指代码的执行过程 进程-》资源的申请与销毁的过程 02 进程vs线程 1、 内存共享or隔离 多个进程内存空间彼此隔离 同一进程下的多个线程共享该进程内的数据 2、创建速度 造线程的速度要远远快于造进程
# 主进程等子进程是因为主进程要给子进程收尸 # 进程必须等待其内部所有线程都运行完毕才结束 # from threading import Thread # import time # # def task(name): # print(‘%s is running‘ %name) # time.sleep(3) # print(‘%s is done‘ %name) # if __name__ == ‘__main__‘: # t=Thread(target=task,args=(‘子线程‘,)) # t.start() # print(‘主‘) # from threading import Thread,current_thread,active_count,enumerate import time def task(): print(‘%s is running‘ % current_thread().name) time.sleep(3) print(‘%s is done‘ % current_thread().name) if __name__ == ‘__main__‘: t = Thread(target=task,name=‘xxx‘) t.start() # t.join() # print(t.is_alive()) # print(t.getName()) # print(t.name) # print(‘主‘,active_count()) # print(enumerate()) # t.join() current_thread().setName(‘主线程‘) print(‘主‘,current_thread().name)
守护线程
# 守护线程会在本进程内所有非守护的线程都死掉了才跟着死 # 即: # 守护线程其实守护的是整个进程的运行周期(进程内所有的非守护线程都运行完毕) # from threading import Thread,current_thread # import time # # # def task(): # print(‘%s is running‘ % current_thread().name) # time.sleep(3) # print(‘%s is done‘ % current_thread().name) # # # if __name__ == ‘__main__‘: # t = Thread(target=task,name=‘守护线程‘) # t.daemon=True # t.start() # print(‘主‘) from threading import Thread import time def foo(): print(123) time.sleep(3) print("end123") def bar(): print(456) time.sleep(1) print("end456") t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon=True t1.start() t2.start() print("main-------") ‘‘‘ 123 456 main------- end456 ‘‘‘
线程VS进程
#1、线程的开启速度快 # from threading import Thread # from multiprocessing import Process # import time # # def task(name): # print(‘%s is running‘ %name) # time.sleep(3) # print(‘%s is done‘ %name) # # if __name__ == ‘__main__‘: # t=Thread(target=task,args=(‘子线程‘,)) # # t=Process(target=task,args=(‘子进程‘,)) # t.start() # print(‘主‘) #2、同一进程下的多个线程共享该进程内的数据 # from threading import Thread # import time # # x=100 # def task(): # global x # x=0 # # if __name__ == ‘__main__‘: # t=Thread(target=task,) # t.start() # # time.sleep(3) # t.join() # print(‘主‘,x) # 查看pid from threading import Thread import time,os def task(): print(os.getpid()) if __name__ == ‘__main__‘: t=Thread(target=task,) t.start() print(‘主‘,os.getpid())
线程互斥锁
from threading import Thread,Lock import time mutex=Lock() x=100 def task(): global x # mutex.acquire() temp=x time.sleep(0.1) x=temp-1 # mutex.release() if __name__ == ‘__main__‘: t_l=[] start=time.time() for i in range(100): t=Thread(target=task) t_l.append(t) t.start() for t in t_l: t.join() stop=time.time() print(x,stop-start) # 打印结果为 99 0.1123046875 # 这说明同一进程下的线程数据是共享的
信号量
信号量:限制的是同一进程下并发执行的任务数(其本质也是锁,同一时间可以运行多个任务) 而互斥锁同一时间只能运行一个任务 # 信号量是控制同一时刻并发执行的任务数 from threading import Thread,Semaphore,current_thread import time,random sm=Semaphore(5) # 控制同一个时刻并发运行的多个任务个数 def task(): with sm: # with sm 其意思是:sm.acquire() (上锁) sm.release()(解锁) print(‘%s 正在上厕所‘ %current_thread().name) time.sleep(random.randint(1,4)) if __name__ == ‘__main__‘: for i in range(20): t=Thread(target=task) t.start()
以上是关于死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量的主要内容,如果未能解决你的问题,请参考以下文章
python 线程(创建2种方式,守护进程,锁,死锁,递归锁,GIL锁,其他方式)
并发编程8 线程的创建&验证线程之间数据共享&守护线程&线程进程效率对比&锁(死锁/递归锁)