• python3 线程与线程之间数据是共享的(锁和死锁)


    线程与线程之间数据是共享的

    from threading import Thread
    
    
    def func(lst, name):
        lst.append(66)
        print(name, lst)
    
    
    if __name__ == '__main__':
        lst = [1, 2]
        t1 = Thread(target=func, args=(lst, "线程1"))
        t2 = Thread(target=func, args=(lst, "线程2"))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print("主线程结束", lst)

    执行结果:

    线程1 [1, 2, 66]
    线程2 [1, 2, 66, 66]
    主线程结束 [1, 2, 66, 66]

    带有global的线程与线程之间的数据共享情况

    from threading import Thread
    
    
    def func(name):
        global n
        print(f"{name}开始,n={n}")
        n = 0
        print(f"{name}结束,n={n}")
    
    
    if __name__ == '__main__':
        n = 100
        t1 = Thread(target=func, args=("线程1",))
        t1.start()
        t1.join()
        print(f"主线程结束,n={n}")

    执行结果:

    线程1开始,n=100
    线程1结束,n=0
    主线程结束,n=0

    接下来看一个由于线程之间的数据是共享而引发问题

    from threading import Thread
    
    
    def func(name):
        print(f"{name}开始")
        global n
        for i in range(100000):
            n += 1
        print(f"{name}结束,n={n}")
    
    
    if __name__ == '__main__':
        n = 0
        t1 = Thread(target=func, args=("线程1",))
        t2 = Thread(target=func, args=("线程2",))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(f"主线程结束,n={n}")

    执行结果:

    线程1开始
    线程2开始
    线程1结束,n=165337
    线程2结束,n=147914
    主线程结束,n=147914

    最终的结果不是我们预期的200000

    解决线程与线程之间数据共享导致的问题:加锁

    from threading import Thread, Lock
    
    
    def func(name, lock: Lock):  # 传递lock,后面添加: Lock表示是Lock类型的是为了上锁和释放锁的时候会有方法提示功能
        print(f"{name}开始")
        global n
        for i in range(100000):
            lock.acquire()  # 上锁
            n += 1
            lock.release()  # 释放锁
        print(f"{name}结束,n={n}")
    
    
    if __name__ == '__main__':
        lock = Lock()  # 创建一把锁
        n = 0
        t1 = Thread(target=func, args=("线程1", lock))
        t2 = Thread(target=func, args=("线程2", lock))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(f"主线程结束,n={n}")

    执行结果:

    线程1开始
    线程2开始
    线程1结束,n=167229
    线程2结束,n=200000
    主线程结束,n=200000

    只看最终结果就行,因为线程1和线程2是并行执行的。

    线程与线程之间数据共享(加锁)

    from threading import Thread, Lock
    
    
    n = 0
    def func(lock, name):
        lock.acquire()
        global n
        for i in range(1000000):
            n += 1
        print("%s拿到了锁" % name)
        lock.release()
    
    
    if __name__ == '__main__':
        lock = Lock()  # 线程锁
        t1 = Thread(target=func, args=(lock, "线程1"))
        t2 = Thread(target=func, args=(lock, "线程2"))
        t3 = Thread(target=func, args=(lock, "线程3"))
        t1.start()
        t2.start()
        t3.start()
        t1.join()
        t2.join()
        t3.join()
        print(n)

    运行结果:

    线程1拿到了锁
    线程2拿到了锁
    线程3拿到了锁
    3000000

    死锁现象

    from threading import Thread, Lock
    
    
    def func(name, lock: Lock):  # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能
        print(f"{name}开始")
        lock.acquire()  # 上锁
        lock.acquire()  # 上锁
        print(f"{name}被锁住了")
        lock.release()  # 释放锁
        lock.release()  # 释放锁
        print(f"{name}结束")
    
    
    if __name__ == '__main__':
        lock = Lock()  # 创建一把锁
        t1 = Thread(target=func, args=("线程1", lock))
        t2 = Thread(target=func, args=("线程2", lock))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(f"主线程结束")

    执行结果:

    线程1开始
    线程2开始

    程序一直执行不完,因为程序被锁住了。

    解决死锁--->使用递归锁RLock

    from threading import Thread, RLock
    
    
    def func(name, lock: RLock):  # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能
        print(f"{name}开始")
        lock.acquire()  # 上锁
        lock.acquire()  # 上锁
        print(f"{name}被锁住了")
        lock.release()  # 释放锁
        lock.release()  # 释放锁
        print(f"{name}结束")
    
    
    if __name__ == '__main__':
        lock = RLock()  # 创建一把锁
        t1 = Thread(target=func, args=("线程1", lock))
        t2 = Thread(target=func, args=("线程2", lock))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(f"主线程结束")

    执行结果:

    线程1开始
    线程1被锁住了
    线程1结束
    线程2开始
    线程2被锁住了
    线程2结束
    主线程结束

    完美解决死锁的问题,切记锁可以保证数据的安全性,但是效率会降低,相当于把并行改为了串行。

    死锁可以想成两个人围着桌子吃饭,两个人的中间各放着一根的筷子,两根筷子在一起才能吃饭,此时,两个人都想吃饭,但是都抓着筷子不放开,结果谁也吃不上饭,就僵死在那了。

  • 相关阅读:
    中断解析
    中断分类
    中断分类
    在iOS开发中使用FMDB
    大数据权限授权管理框架:Apache Sentry和Ranger
    Flink FileSystem的connector分析
    Flink FileSystem的connector分析
    Flink JobManager的HA原理分析
    Flink JobManager的HA原理分析
    Flink的State概述
  • 原文地址:https://www.cnblogs.com/lilyxiaoyy/p/12055146.html
Copyright © 2020-2023  润新知