7 死锁,递归锁,信号量,Event事件,线程Queue

一、死锁现象与递归锁

进程也是有死锁的

所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,

它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,

如下就是死锁

死锁-------------------
from  threading import Thread,Lock,RLock
import time
mutexA = Lock()
mutexB = Lock()
class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()
    def f1(self):
        mutexA.acquire()
        print(‘\033[33m%s 拿到A锁 ‘%self.name)
        mutexB.acquire()
        print(‘\033[45%s 拿到B锁 ‘%self.name)
        mutexB.release()
        mutexA.release()
    def f2(self):
        mutexB.acquire()
        print(‘\033[33%s 拿到B锁 ‘ % self.name)
        time.sleep(1)  #睡一秒就是为了保证A锁已经被别人那到了
        mutexA.acquire()
        print(‘\033[45m%s 拿到B锁 ‘ % self.name)
        mutexA.release()
        mutexB.release()
if __name__ == ‘__main__‘:
    for i in range(10):
        t = MyThread()
        t.start() #一开启就会去调用run方法

死锁现象

那么怎么解决死锁现象呢?

解决方法,递归锁:在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。

直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁

mutexA=mutexB=threading.RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,<br>则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止

# 2.解决死锁的方法--------------递归锁
from  threading import Thread,Lock,RLock
import time
mutexB = mutexA = RLock()
class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()
    def f1(self):
        mutexA.acquire()
        print(‘\033[33m%s 拿到A锁 ‘%self.name)
        mutexB.acquire()
        print(‘\033[45%s 拿到B锁 ‘%self.name)
        mutexB.release()
        mutexA.release()
    def f2(self):
        mutexB.acquire()
        print(‘\033[33%s 拿到B锁 ‘ % self.name)
        time.sleep(1)  #睡一秒就是为了保证A锁已经被别人拿到了
        mutexA.acquire()
        print(‘\033[45m%s 拿到B锁 ‘ % self.name)
        mutexA.release()
        mutexB.release()
if __name__ == ‘__main__‘:
    for i in range(10):
        t = MyThread()
        t.start() #一开启就会去调用run方法

解决死锁

二、信号量Semaphore(其实也是一把锁)

Semaphore管理一个内置的计数器

Semaphore与进程池看起来类似,但是是完全不同的概念。

进程池:Pool(4),最大只能产生四个进程,而且从头到尾都只是这四个进程,不会产生新的。

信号量:信号量是产生的一堆进程/线程,即产生了多个任务都去抢那一把锁

from threading import Thread,Semaphore,currentThread
import time,random
sm = Semaphore(5) #运行的时候有5个人
def task():
    sm.acquire()
    print(‘\033[42m %s上厕所‘%currentThread().getName())
    time.sleep(random.randint(1,3))
    print(‘\033[31m %s上完厕所走了‘%currentThread().getName())
    sm.release()
if __name__ == ‘__main__‘:
    for i in range(20):  #开了10个线程 ,这20人都要上厕所
        t = Thread(target=task)
        t.start()

Semaphore举例

hread-1上厕所
 Thread-2上厕所
 Thread-3上厕所
 Thread-4上厕所
 Thread-5上厕所
 Thread-3上完厕所走了
 Thread-6上厕所
 Thread-1上完厕所走了
 Thread-7上厕所
 Thread-2上完厕所走了
 Thread-8上厕所
 Thread-6上完厕所走了
 Thread-5上完厕所走了
 Thread-4上完厕所走了
 Thread-9上厕所
 Thread-10上厕所
 Thread-11上厕所
 Thread-9上完厕所走了
 Thread-12上厕所
 Thread-7上完厕所走了
 Thread-13上厕所
 Thread-10上完厕所走了
 Thread-8上完厕所走了
 Thread-14上厕所
 Thread-15上厕所
 Thread-12上完厕所走了
 Thread-11上完厕所走了
 Thread-16上厕所
 Thread-17上厕所
 Thread-14上完厕所走了
 Thread-15上完厕所走了
 Thread-17上完厕所走了
 Thread-18上厕所
 Thread-19上厕所
 Thread-20上厕所
 Thread-13上完厕所走了
 Thread-20上完厕所走了
 Thread-16上完厕所走了
 Thread-18上完厕所走了
 Thread-19上完厕所走了

运行结果

三、Event

线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行

from threading import Event
Event.isSet() #返回event的状态值
Event.wait() #如果 event.isSet()==False将阻塞线程;
Event.set() #设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
Event.clear() #恢复

四、定时器(Timer)

指定n秒后执行某操作

from threading import Timer
def func(n):
    print(‘hello,world‘,n)
t = Timer(3,func,args=(123,))  #等待三秒后执行func函数,因为func函数有参数,那就再传一个参数进去
t.start()

五、线程queue

queue队列 :使用import queue,用法与进程Queue一样

queue.Queue(maxsize=0) #先进先出

 

queue.LifoQueue(maxsize=0)#先进后出

 

queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

# ----------------
‘‘‘3.put进入一个元组,元组的第一个元素是优先级
(通常也可以是数字,或者也可以是非数字之间的比较)
数字越小,优先级越高‘‘‘
q = queue.PriorityQueue()
q.put((20,‘a‘))
q.put((10,‘b‘))  #先出来的是b,数字越小优先级越高嘛
q.put((30,‘c‘))
print(q.get())
print(q.get())
print(q.get())

六、多线程性能测试

1.多核也就是多个CPU(1)cpu越多,提高的是计算的性能(2)如果程序是IO操作的时候(多核和单核是一样的),再多的cpu也没有意义。2.实现并发第一种:一个进程下,开多个线程第二种:开多个进程3.多进程:   优点:可以利用多核   缺点:开销大4.多线程   优点:开销小   缺点:不可以利用多核5多进程和多进程的应用场景   1.计算密集型:也就是计算多,IO少     如果是计算密集型,就用多进程(如金融分析等)   2.IO密集型:也就是IO多,计算少     如果是IO密集型的,就用多线程(一般遇到的都是IO密集型的)

原文地址:https://www.cnblogs.com/edison-chen/p/9777413.html

时间: 2024-07-30 18:53:25

7 死锁,递归锁,信号量,Event事件,线程Queue的相关文章

并发编程---死锁||递归锁---信号量---Event事件---定时器

死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁:  RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 from threading import Thread,Lock import time mutexA = Lock() mutexB = Lock() class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self):

Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池

目录 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 2.死锁现象与递归锁 2.1死锁现象 2.2递归锁 3.信号量 4.GIL全局解释器锁 4.1背景 4.2为什么加锁 5.GIL与Lock锁的区别 6.验证计算密集型IO密集型的效率 6.1 IO密集型 6.2 计算密集型 7.多线程实现socket通信 7.1服务端 7.2客户端 8.进程池,线程池 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 #生产者消

13 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件  queue队列 生产者消费者模型 Queue队列 开发一个线程池

本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Queue队列 开发一个线程池 进程 语法 进程间通讯 进程池 操作系统发展史 手工操作(无操作系统) 1946年第一台计算机诞生--20世纪50年代中期,还未出现操作系统,计算机工作采用手工操作方式. 手工操作程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把

线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁

线程(from threading import Thread):CPU调度的最小单位 线程的两种创建方式:方式一: 1 from threading import Thread 2 def f1(i): 3 print(i) 4 if __name__ == '__main__': 5 for i in range(10): 6 t = Thread(target=f1,args=(i,)) 7 t.start() 8 print('主线程') 方式二: 1 from threading im

并发&amp;并行 同步&amp;异步 GIL 任务 同步锁 死锁 递归锁

# 并发&并行 同步&异步 GIL 任务 同步锁 死锁 递归锁 # 并发:是指系统具有处理多个任务(动作)的能力 # 并行:是指系统具有 同时 处理多个任务(动作)的能力 # 同步:当进程执行到一个IO(等待外部数据)的时候,需要等待外部数据接收完 # 异步:当进程执行到一个IO(等待外部数据)的时候,不需要等待外部数据接收完,还可以做其它的处理 # GIL: 全局解释器锁 在python中,无论你启多少个线程,你有多少个cpu,python在执行的时候在同一时刻只请允许一个线程运行 #

python开发线程:死锁和递归锁&amp;信号量&amp;定时器&amp;线程queue&amp;事件evevt

一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 from threading import Thread,Lock import time mutexA=Lock() mutexB=Lock() class MyThread(Thread):

python-GIL、死锁递归锁及线程补充

一.GIL介绍 GIL全称 Global Interpreter Lock ,中文解释为全局解释器锁.它并不是Python的特性,而是在实现python的主流Cpython解释器时所引入的一个概念,CIL本质上就是一把互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,从而保证数据的安全性. 注:每次执行python程序,都会产生一个独立的进程,进程里除了能看到的若干线程,还有看不见的解释器开启的垃圾回收等解释器级别的线程. #1 所有数据都是共享的,这其中,代码作为一

并发编程8 线程的创建&amp;验证线程之间数据共享&amp;守护线程&amp;线程进程效率对比&amp;锁(死锁/递归锁)

1.线程理论以及线程的两种创建方法 2.线程之间是数据共享的与join方法 3.多线程和多进程的效率对比 4.数据共享的补充线程开启太快 5.线程锁 互斥锁 同步锁 6.死锁现象和递归锁 7.守护线程和守护进程的对比 8.补充 9.GIL锁&GIL锁与线程锁的区别 10.GIL锁补充 11.信号量 时间补充说明 原文地址:https://www.cnblogs.com/studybrother/p/10269278.html

python 线程(创建2种方式,守护进程,锁,死锁,递归锁,GIL锁,其他方式)

###############总结############ 线程创建的2种方式(重点) 进程:资源分配单位    线程:cpu执行单位(实体) 线程的创建和销毁的开销特别小 线程之间资源共享,是同一个进程中的资源共享,会涉及到安全问题,所以需要加锁解决 锁:牺牲了效率,保证了数据安全(重点) 死锁现象:出现在嵌套的时候,双方互相抢对方已经拿到的锁,导致双方互相等待(重点) 递归锁: 解决了死锁现象(重点) rlock 首先本身就是个互斥锁,维护了一个计数器,每次acquire+1,release

同步锁 死锁 递归锁

多线程 同步锁(互斥锁) 解决什么问题? 同步锁解决什么问题? 多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操作,cpu就有可能去执行另外一个线程,另外一个线程拿到的则是之前线程没有处理完的数据,如下 import threading import time count=20 def zx(): global count print(count) time.sleep(0.001) count-=1 t_list=[] for t in rang