Python3之多线程GIL、同步锁、信号量、死锁与递归锁、线程Queue、Event、定时器

GIL与互斥锁再理解

《Python3之多线程GIL、同步锁、信号量、死锁与递归锁、线程Queue、Event、定时器》

线程一要把python代码交给解释器去执行,而此时垃圾回收线程和线程二也需要将自己的任务交给python解释器去执行,为了防止各个线程之间的数据产生冲突,谁拿到GIL锁的权限谁才能执行自己的任务,这就避免了不同任务之间的数据不会产生冲突,这是在同一个进程中加GIL锁会保证数据的安全,不同的数据要加不同的锁

死锁与递归锁

死锁

代码演示

from threading import Thread, Lock
import time
mutexA = Lock()
mutexB = Lock()

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()
        time.sleep(1)
        print('%s 拿到B锁' % self.name)
        mutexA.acquire()
        print('%s 拿到A锁' % self.name)
        mutexA.release()
        mutexB.release()


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

该种情况出现死锁:
《Python3之多线程GIL、同步锁、信号量、死锁与递归锁、线程Queue、Event、定时器》

代码讲解

由于Thread-1创建的比较快,所以Thread-1先抢到A锁,继而顺利成章的拿到B锁,当Thread-1释放掉A锁时,另外9个线程抢A锁,于此同时,Thread-1抢到B锁,而此时Thread-2抢到A锁,这样Thread-1、Thread-2就等待彼此把锁释放掉,这样程序就卡住了,解决这个问题就用到了递归锁。

递归锁

代码演示

from threading import Thread, Lock, RLock
import time

# mutexA = Lock()
# mutexB = Lock()
mutexA = mutexB = RLock()


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()
        time.sleep(1)
        print('%s 拿到B锁' % self.name)
        mutexA.acquire()
        print('%s 拿到A锁' % self.name)
        mutexA.release()
        mutexB.release()


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

代码讲解

递归锁时通过计数完成对锁的控制的,当acquire一次,count+=1,release一次,count-=1,当count=0,所有的线程都可以对锁进行抢夺。从而避免了死锁的产生。

信号量Semaphore

代码演示

from threading import Thread, Semaphore, currentThread
import time
smph = Semaphore(5)


def do_task():
    smph.acquire()
    print('\033[45m%s\033[0m 获得了权限' % currentThread().name)
    time.sleep(2)
    print('\033[46m%s\033[0m 放弃了权限' % currentThread().name)
    smph.release()


if __name__ == '__main__':
    for i in range(10):
        t = Thread(target=do_task, )
        t.start()

代码效果

《Python3之多线程GIL、同步锁、信号量、死锁与递归锁、线程Queue、Event、定时器》

代码讲解

信号量Semaphore本质也是一把锁,但是这把锁可以限定允许多个任务同时执行任务,但是不能超出规定的限制,下面的代码参数5就代表可以执行5个任务,如果第6个任务要执行,必须等5个任务中的一个结束,然后第六个才能进入执行。

smph = Semaphore(5)

这有点像进程池,只不过进程池规定了进程数量,多个任务进入进程池只能有数量一定的进程进行处理。,但是Semaphore可以产生多个线程。

线程Queue

队列Queue

代码演示

import queue

q = queue.Queue()
q.put('1')
q.put(1)
q.put({'a': 1})

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

代码讲解

  1. 先进先出
  2. 可以存放任意类型数据

堆栈Queue

代码演示

import queue
q = queue.LifoQueue()
q.put(1)
q.put('1')
q.put({'a': 1})

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

代码讲解

  1. 可以存放任意数据类型
  2. Lifo代表后进先出

优先级Queue

代码演示

import queue

q = queue.PriorityQueue()
q.put((10, 'Q'))
q.put((30, 'Z'))
q.put((20, 'A'))

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

代码讲解

  1. 存放的数据是元组类型,带有优先级数字越小优先级越高。
  2. 数据优先级高的优先被取出。
  3. 用于VIP用户数据优先被取出场景,因为上面两种都要挨个取出。

Event

代码演示

from threading import Thread, Event, currentThread
import time

e = Event()


def traffic_lights():
    time.sleep(5)
    e.set()


def cars():
    print('\033[45m%s\033[0m is waiting' % currentThread().name)
    e.wait()
    print('\033[45m%s\033[0m is running' % currentThread().name)


if __name__ == '__main__':
    for i in range(10):
        t = Thread(target=cars, )
        t.start()
    traffic_lights = Thread(target=traffic_lights, )
    traffic_lights.start()

代码讲解

首先创建10个线程代表10辆车正在等信号灯,创建1个线程代表信号灯,当10辆汽车被创建后就等着信号灯发信号起跑,当遇到e.wait()时程序被挂起,等待信号灯变绿,而e.set()就是来改变这个状态让信号灯变绿,当e.set被设置后cars等到了信号,就可以继续往后跑了,代码可以继续执行了。e.set()默认False,e.set()调用后值变为True,e.wait()接收到后程序由挂起变为可执行。

应用场景

代码演示

from threading import Thread, Event, currentThread
import time

e = Event()


def check_sql():
    print('%s is checking mySQL' % currentThread().name)
    time.sleep(5)
    e.set()


def link_sql():
    count = 1
    while not e.is_set():#e.isSet是一个绑定方法,自带布尔值为True,e.is_set()默认值为False
        e.wait(timeout=1)
        print('%s is trying %s' % (currentThread().name, count))
        if count > 3:
            raise ConnectionError('连接超时')
        count += 1
    print('%s is connecting' % currentThread().name)


if __name__ == '__main__':
    t_check = Thread(target=check_sql, )
    t_check.start()
    for i in range(3):
        t_link = Thread(target=link_sql, )
        t_link.start()

代码讲解

  1. 数据库远程连接
  2. e.isSet是一个绑定方法,自带布尔值为True,e.is_set()默认值为False

定时器

代码演示

from threading import Timer


def deal_task(n):
    print('%s 我被执行了~' % n)


t = Timer(3, deal_task, args=(10,))
t.start()

代码讲解

注意传参时必须是元组形式

    原文作者:Quincy379
    原文地址: https://blog.csdn.net/qq_33733970/article/details/77719427
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞