python之路---并发编程之线程&死锁现象与递归锁/Event/线程Queue

死锁现象

两个或两个以上的进程或线程在执行任务的过程中,因为争抢资源而发生相互等待的现象

class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        lock_1.acquire()
        print('%s拿到1号锁' % self.name)
        lock_2.acquire()
        print('%s拿到2号锁' % self.name)
        lock_1.release()
        lock_2.release()

    def f2(self):
        lock_2.acquire()
        print('%s拿到2号锁' % self.name)
        time.sleep(1)
        lock_1.acquire()
        print('%s拿到1号锁' % self.name)
        lock_1.release()
        lock_2.release()


lock_1 = Lock()
lock_2 = Lock()

for i in range(10):
    obj = MyThread()
    obj.start()
print('存活的线程数:',active_count())

由于一个线程拿着互斥锁2(准备拿互斥锁1),而另一个线程拿着互斥锁1(准备拿互斥锁2),发生的阻塞(死锁现象)

解决方法

在python中为了允许同一进程中多次请求一个资源而引入递归所的概念

RLock内部有一个Lock与count变量,count用来记录这个锁被acquire的次数(允许被多次acquire),直到一个线程的所有acquire都被release,其它线程才能去获得这个锁

class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        lock_1.acquire()
        print('%s拿到1号锁' % self.name)
        lock_2.acquire()
        print('%s拿到2号锁' % self.name)
        lock_1.release()
        lock_2.release()

    def f2(self):
        lock_2.acquire()
        print('%s拿到2号锁' % self.name)
        time.sleep(1)
        lock_1.acquire()
        print('%s拿到1号锁' % self.name)
        lock_1.release()
        lock_2.release()


lock_1 = lock_2 = RLock()

if __name__ == '__main__':
    for i in range(10):
        obj = MyThread()
        obj.start()

这样就不会发生死锁现象

Event

由于线程是独立运行的且状态不可预测,如果当程序中的某一个线程的下一步运行是需要另一个线程的某个状态来触发的,那么就可以使用Event对象来解决

当一个线程等待一个Event对象时(Event对象的信号标志位为假),这个线程就会发生阻塞直至标志位变为真,而当我们将一个线程中event对象的信号标志位变为真,就会触发所有等待这个event对象的线程的执行

# Event的用法
event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

一个例子

import time
from threading import Thread,Event


def light():
    time.sleep(5)
    print()
    print('红灯变为绿灯...')
    print()
    event.set()


def highway(name):
    if event.isSet() is False:
        print('%s在等待....'%name)
    event.wait()
    print('%s通过路口...'%name)


event = Event()
t1 = Thread(target=light)
t1.start()
for i in range(10):
    t = Thread(target=highway,args=('车辆%s'%i,))
    t.start()

此外,如果现在多个线程有连Mysql的需求,而我们想要让其在Mysql服务开启时才去连接,这时候我们就可以使用Event对象去控制这些线程

Queue

import queue

print('队列'.center(20,'-'))
# 队列,先进先出
q = queue.Queue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

print('堆栈'.center(20,'-'))
# 堆栈先进后出
q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

# 优先级高的先出,数字越小,优先级越高(支持负数)
print('优先级'.center(20,'-'))
q = queue.PriorityQueue()
q.put((0,'VIP'))
q.put((-1,'SVIP'))
q.put((1,'public'))

print(q.get())
print(q.get())
print(q.get())

猜你喜欢

转载自blog.csdn.net/ltfdsy/article/details/82496390