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

Posted dangrui0725

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发&并行 同步&异步 GIL 任务 同步锁 死锁 递归锁相关的知识,希望对你有一定的参考价值。

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

# 并发:是指系统具有处理多个任务(动作)的能力
# 并行:是指系统具有 同时 处理多个任务(动作)的能力

# 同步:当进程执行到一个IO(等待外部数据)的时候,需要等待外部数据接收完
# 异步:当进程执行到一个IO(等待外部数据)的时候,不需要等待外部数据接收完,还可以做其它的处理

# GIL: 全局解释器锁 在python中,无论你启多少个线程,你有多少个cpu,python在执行的时候在同一时刻只请允许一个线程运行
# 任务:IO密集型(python的多线程是有意义的,或使用多进程+协程) 计算密集型(python的多线程就不推荐,python就不适用了)

# 同步锁
import threading, time

num = 100


def sub():
    global num
    temp = num
    time.sleep(0.00001)
    num = temp - 1


l = []  # 定义一个空列表
for i in range(100):  # 循环100次
    t = threading.Thread(target=sub)  # 通过循环创建100个线程t对象并放入列表中
    t.start()
    l.append(t)

for t in l:  # 循环列表,让每一个线程对象t执行join()
    t.join()

print(num)  # 99 居然不是0,问题在哪里?

# 因为此时是IO操作,当第一个线程取到100后要睡1秒,这时还没有减1,这时第二个线程又来取值,值还是100,只要cpu执行速度越快,所有的线程来取值时都是100,意味着100个线程都拿到num为100
# 如果sleep(0.00001),这时最终值又会变为92。这里的值与cpu调度的各线程IO操作的时间有关,sleep时间越短,各个线程拿到num为100时的情况就越少
# 解决方法,加上同步锁,在同一时间只允许一个线程对num操作
import threading, time

num = 100


def sub():
    global num

    lock.acquire()  # 加锁
    temp = num
    time.sleep(0.00001)
    num = temp - 1
    lock.release()  # 解锁


l = []  # 定义一个空列表
lock = threading.Lock()  # 创建同步锁
for i in range(100):  # 循环100次
    t = threading.Thread(target=sub)  # 通过循环创建100个线程t对象并放入列表中
    t.start()
    l.append(t)

for t in l:  # 循环列表,让每一个线程对象t执行join()
    t.join()

print(num)  # 0

# 一个死锁的例子 第一个线程需要A锁(A锁已被第二个线程占用),第二个线程需要B锁(B锁已被第一个线程占用)。结果谁也不让造成死锁
import threading, time


class MyThread(threading.Thread):

    def actionA(self):
        A.acquire()
        print(self.name, gotA, time.ctime())
        time.sleep(2)
        B.acquire()
        print(self.name, gotB, time.ctime())
        time.sleep(2)
        B.release()
        A.release()

    def actionB(self):
        B.acquire()
        print(self.name, gotB, time.ctime())
        time.sleep(2)
        A.acquire()
        print(self.name, gotA, time.ctime())
        time.sleep(2)
        A.release()
        B.release()

    def run(self):
        self.actionA()
        self.actionB()


if __name__ == __main__:
    A = threading.Lock()
    B = threading.Lock()

    l = []
    for i in range(5):
        t = MyThread()
        t.start()
        l.append(t)

    for i in l:
        t.join()
    print(end...)

# 解决死锁的方案,使用递归锁

import threading, time


class MyThread(threading.Thread):

    def actionA(self):
        r_lock.acquire()
        print(self.name, gotA, time.ctime())
        time.sleep(2)
        r_lock.acquire()
        print(self.name, gotB, time.ctime())
        time.sleep(2)
        r_lock.release()
        r_lock.release()

    def actionB(self):
        r_lock.acquire()
        print(self.name, gotB, time.ctime())
        time.sleep(2)
        r_lock.acquire()
        print(self.name, gotA, time.ctime())
        time.sleep(2)
        r_lock.release()
        r_lock.release()

    def run(self):
        self.actionA()
        self.actionB()


if __name__ == __main__:
    r_lock = threading.RLock()  # 这里创建的是递归锁,将原来的两把锁AB换成一把锁
    # 哪个线程拿到r_lock锁,只有等它完全释放后,其它的线程才能再拿这个锁

    l = []
    for i in range(5):
        t = MyThread()
        t.start()
        l.append(t)

    for i in l:
        t.join()

    print(end...)

 

以上是关于并发&并行 同步&异步 GIL 任务 同步锁 死锁 递归锁的主要内容,如果未能解决你的问题,请参考以下文章

GIL 锁

GIL,同步与异步

python 同步异步,并发并行,同步锁

python-并发并行同步异步同步锁

并发与同步异步的概念

并行,并发,串行,同步,异步,阻塞,非阻塞,同步阻塞,同步非阻塞,异步阻塞,异步非阻塞