• python多线程锁lock/Rlock/BoundedSemaphore/Condition/Event


    import time
    import threading
    
    lock = threading.RLock()
    
    n = 10
    
    
    def task(arg):
        # 加锁,此区域的代码同一时刻只能有一个线程执行
        lock.acquire()
    
        # 获取当前线程对象
        thread_obj = threading.current_thread()
        # 获取当前线程名字
        name = thread_obj.getName()
    
        global n
        n = arg
        time.sleep(1)
        print('当前线程', name, '修改后n的值为:', n)
    
        # 释放锁
        lock.release()
    
    
    for i in range(5):
        t = threading.Thread(target=task, args=(i,))
        t.setName(str(i))
        t.start()
    

    '''
    期望结果-->加锁情况:
    当前线程 0 修改后n的值为: 0
    当前线程 1 修改后n的值为: 1
    当前线程 2 修改后n的值为: 2
    当前线程 3 修改后n的值为: 3
    当前线程 4 修改后n的值为: 4
    '''

    '''
    不期望结果-->没加锁情况
    当前线程 0 修改后n的值为: 4
    当前线程 1 修改后n的值为: 4
    当前线程 2 修改后n的值为: 4
    当前线程 3 修改后n的值为: 4
    当前线程 4 修改后n的值为: 4
    '''

    引子:为什么要加锁?

    需求:每个线程将一个数字添加到列表,然后取出自己放的数字,线程结束.
    希望得到的结果如下:
    '''
    0 0
    1 1
    2 2
    3 3
    4 4
    '''
    代码:
    import threading
    import time
    lst = []
    def func(arg):
    # 线程安全
    lst.append(arg)
    time.sleep(0.1)
    m = lst[-1]
    print(arg,m)
    for i in range(5):
    t = threading.Thread(target=func,args=(i,))
    t.start()
    总结:
    从上面这个例子看,如果不加锁,每个线程放进去自己的数字,再取最后一个数字,就不一定是自己放的,因为这个时间,可能其他线程也放进去了,你拿到的,可能是其他线程放的.所以这个时候就需要加锁,限制一个线程没操作完,另一个绝对不能动.

    1.锁:Lock(1次放1个)

    import threading
    import time
    lst = []
    lock = threading.Lock()
    def func(arg):
    lock.acquire()
    lst.append(arg)
    time.sleep(0.1)
    m = lst[-1]
    lock.release()
    for i in range(5):
    t = threading.Thread(target=func,args=(i,))
    t.start()

    2.锁:RLock(1次放1个)

    import threading
    import time
    
    lst = []
    lock = threading.RLock()
    
    
    def func(arg):
        lock.acquire()
        lock.acquire()
        lst.append(arg)
        time.sleep(0.1)
        m = lst[-1]
        print(arg, m)
        lock.release()
        lock.release()
    
    
    for i in range(5):
        t = threading.Thread(target=func, args=(i,))
        t.start()
    

    PS:Lock和RLock的区别是RLock可以多次加锁.

    3.锁:BoundedSemaphore(1次放N个)信号量

    import time
    import threading
    
    lst = []
    # 一次放3个
    lock = threading.BoundedSemaphore(3)
    
    
    def func(arg):
        lock.acquire()
        lst.append(arg)
        m = lst[-1]
        print(arg, m)
        time.sleep(3)
        lock.release()
    
    
    for i in range(10):
        t = threading.Thread(target=func, args=(i,))
        t.start()
    

    4.锁:Condition(1次放x个)

    方法1:

    import time
    import threading
    
    lst = []
    lock = threading.Condition()
    
    
    def func(arg):
        print('start...')
        lock.acquire()
        lock.wait()
        lst.append(arg)
        m = lst[-1]
        print(arg, m)
        time.sleep(1)
        lock.release()
    
    
    for i in range(10):
        t = threading.Thread(target=func, args=(i,))
        t.start()
    
    while True:
        num = int(input('>>>:'))
        lock.acquire()
        # 控制放几个线程执行,比如写3个,但是线程实际2个,那就是2个了
        lock.notify(num)  # 3
        lock.release()
    

    方法2:

    import time
    import threading
    
    lock = threading.Condition()
    
    
    def func1():
        print('start...')
        input('>>>:')
        return True
    
    
    def func2(arg):
        print('
    线程进来了')
        # func1作为执行条件
        lock.wait_for(func1)
        print(arg)
        time.sleep(1)
    
    
    for i in range(10):
        t = threading.Thread(target=func2, args=(i,))
        t.start()
    

    5.锁:Event(1次放所有)

    import threading
    
    lock = threading.Event()
    
    
    def func(arg):
        print('线程来了')
        # 加锁:红灯
        lock.wait()
        print(arg)
    
    
    for i in range(10):
        t = threading.Thread(target=func, args=(i,))
        t.start()
    input('>>>:')
    lock.set()  # 绿灯
    lock.clear()  # 再次变红灯
    
    for i in range(10):
        t = threading.Thread(target=func, args=(i,))
        t.start()
    input('>>>')
    lock.set()
    

    总结:
    线程安全,列表和字典线程安全;
    为什么要加锁?
    - 非线程安全
    - 控制一段代码

  • 相关阅读:
    LevelDB的源码阅读(四) Compaction操作
    LevelDB的源码阅读(三) Get操作
    LevelDB的源码阅读(三) Put操作
    高级测试/测试开发技能
    IM测试功能点
    深入理解--SSM框架中Dao层,Mapper层,controller层,service层,model层,entity层都有什么作用
    Jmeter非GUI分布式测试
    全套支付宝系统架构(内部架构图)【收藏】
    Jmeter
    报表类相关测试范围总结
  • 原文地址:https://www.cnblogs.com/apollo1616/p/10350923.html
Copyright © 2020-2023  润新知