Threading Lock RLock

创建一个线程

  1. 最简单的一个线程

    from threading import Thread
    
    
    def count():
        for i in range(10):
            print(i)
    
    
    if __name__ == '__main__':
        t = Thread(target=count)
        t.start()
    
    # 运行结果:
    # 0,1,2,3...
    
  2. 继承Thread创建一个线程

    from threading import Thread
    
    
    class MyThread(Thread):
        def __init__(self, num):
            super().__init__()  # 或写成 Thread.__init__(self)
            self.num = num
    
        def run(self):
            for i in range(self.num):
                print(i)
    
    
    if __name__ == '__main__':
        t = MyThread(10)
        t.start()
    
    # 运行结果:
    # 0,1,2,3...
    
  3. thread.join()方法
    阻塞当前线程,待当前线程结束后再往下执行 主线程或者另一个子线程

    a. 子线程阻塞,待子线程结束之后,主线程继续执行

    import time
    from threading import Thread
    
    
    def count():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    
    if __name__ == '__main__':
        t = Thread(target=count)
        t.start()
        t.join()
        print('hhh')
    
    # 运行结果 1,2,3,4,5...hhh
    

    b. 第一个子线程执行结束后第二个子线程继续执行

    import time
    from threading import Thread
    
    
    def count_up():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    
    def count_down():
        for i in range(10):
            i = 10 - i
            print(i)
            time.sleep(0.5)
    
    
    if __name__ == '__main__':
        t1 = Thread(target=count_up)
        t2 = Thread(target=count_down)
        t1.start()
        t1.join()
        t2.start()
        t2.join()
    
    # 运行结果0,1,2,3,4,5,6,7,8,9,10,9,8....
    
  4. threading.setDamon(True)
    setDamon值默认为False,当setDamon=True的时候,不管子线程有没有结束,只要主线程结束了,子线程就结束

    注意:
    a. setDamon=True必须放在start()函数之前
    b. setDamon=True既可以写t.setDamon(True),也可以Thread(target=count, daemon=True)

    import time
    from threading import Thread
    
    
    def count():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    
    if __name__ == '__main__':
        t = Thread(target=count)
        t.setDaemon(True)
        t.start()
        print('主线程开始,等待2S子线程强制结束')
        time.sleep(2)
        print('主线程结束,子线程结束')
    
  5. threading conclusion

    t = Thread(target=func, args=(1, 2))  # func不可包含(),args为turple类型
    t.start()  # 开始一个子线程
    t.join()  # 阻塞其他线程,当前线程运行结束后继续执行
    t.setDaemon(True)  # 子线程随着主线程退出而退出,默认False
    t.name = 'MyThread'  # 给当前线程命名
    t.getName()  # 获取当前线程名称
    

Lock()

  1. Lock简介
    Lock:当不同的线程会对同一个变量进行操作的时候,如果不能正确控制先后的顺序,则可能会导致变量的值造成不可预测的错误。

    Lock有以下两种方法:

    from threading import Lock
    
    lock = Lock()
    lock.acquire()  # 获取锁
    lock.release()  # 释放锁
    

    当有两个线程同时运行时,假设一个变量 X 首先需要被函数A处理,然后再递交给函数B处理,则:
    a. 在A中首先获取锁lock.acquire(),待A函数处理完成后lock.release()释放锁
    b. B函数获取A函数释放的锁lock.acquire(),B函数使用完成后释放锁

  2. Lock示例
    a. 没有使用锁

    from threading import Thread
    
    
    def lock_test_1():
        global variable
        for _ in range(10):
            variable += 1
            print(variable)
    
    
    def lock_test_2():
        global variable
        for i in range(10):
            variable += 10
            print(variable)
    
    
    if __name__ == '__main__':
        variable = 0
        threads = []
        t1 = Thread(target=lock_test_1)
        t2 = Thread(target=lock_test_2)
        threads.append(t1)
        threads.append(t2)
        for thread in threads:
            thread.start()
    
    # 只要运行足够多的次数,运行的结果就会不一样
    # 期望结果 1,2,3,4,5,6,7,8,9,10,20,30...
    # 实际可能结果 1,11,12...
    

    b. 使用锁后

    import time
    from threading import Thread, Lock
    
    
    def lock_test_1():
        global variable, lock
        lock.acquire()
        for _ in range(10):
            variable += 1
            print(variable)
        lock.release()
    
    
    def lock_test_2():
        global variable, lock
        lock.acquire()
        for i in range(10):
            variable += 10
            print(variable)
        lock.release()
    
    
    if __name__ == '__main__':
        variable = 0
        lock = Lock()
        threads = []
        t1 = Thread(target=lock_test_1)
        t2 = Thread(target=lock_test_2)
        threads.append(t1)
        threads.append(t2)
        for thread in threads:
            thread.start()
    
    # 运行结果永远是 1,2,3,4,5,6,7,8,9,10,20,30...
    
  3. Lock注意事项
    a. 假设AB两个线程,A没有释放锁,B想获取锁,A一直没有释放,B一直就在获取锁的状态,如果A一直不释放锁,就会导致 “死锁”。
    b. with语句可以自动获取锁,在with代码块结束会自动释放锁

    from threading import Thread, Lock
    
    lock = Lock()
    with lock:
        ...
    

    c. 如果对已经释放的锁再次release,会引发RuntimeError

    from threading import Thread, Lock
    
    lock = Lock()
    lock.release()
    
    # Traceback (most recent call last):
    # File "D:/OneDrive/PythonProject/Demos/test.py", line 5, in <module>
    # lock.release()
    # RuntimeError: release unlocked lock
    
  4. Lock总结
    a. 锁有两种状态,locked(被某个线程拿到)和unlocked状态(锁被释放可使用);
    b. 锁的操作方法是acquirerelease;
    c. 如果状态是unlocked,调用acquire会将锁的状态改为locked;
    d. 如果状态是unlocked,调用release会导致RuntimeError;
    e. 如果状态是locked,调用acquire会导致死锁;
    f. 如果状态是locked,调用release会将锁的状态改为unlocked

RLocK()

  1. RLock简介
    RLock在同一个线程中,首先获取锁,在此线程中需要再次使用锁的时候不会造成死锁
    RLock和Lock具有同样的方法

    from threading import RLock
    
    lock = RLock()
    lock.acquire()  # 获取锁
    lock.release()  # 释放锁
    
    
  2. RLock特点
    a. 谁拿到谁释放。如果线程A拿到锁,线程B无法释放这个锁,只有A可以释放;
    b. 同一线程可以多次拿到该锁,即可以acquire多次;
    c. acquire多少次就必须release多少次,只有最后一次release才能改变RLock的状态为unlocked

  3. RLock示例
    a. 使用Lock会卡死

    from threading import RLock, Thread, Lock
    
    
    def count():
        global lock, num
        with lock:  # 获取锁
            for i in range(num):
                print(i)
                with lock:  # 再次获取锁
                    pass
    
    
    if __name__ == '__main__':
        num = 10
        lock = Lock()
        t = Thread(target=count)
        t.start()
    

    b. 使用RLock则可正常运行

    from threading import RLock, Thread, Lock
    
    
    def count():
        global lock, num
        with lock:  # 获取锁
            for i in range(num):
                print(i)
                with lock:  # 再次获取锁
                    pass
    
    
    if __name__ == '__main__':
        num = 10
        lock = RLock()
        t = Thread(target=count)
        t.start()
    
  4. RLock理解
    在同一线程里,RLock只是放松了锁的获取,其他根Lock没有其他不同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值