• Python线程二


    转自:https://www.cnblogs.com/chengd/articles/7770898.html

    1. threading.Lock()

    import threading
    
    balance = 0
    lock = threading.Lock()
    
    def change_it(n):
        # 先存后取,结果应该为0:
        global balance
        balance = balance + n
        balance = balance - n
    
    def run_thread(n):
        for i in range(100000):
            # 先要获取锁:
            lock.acquire()
            try:
                # 放心地改吧:
                change_it(n)
            finally:
                # 改完了一定要释放锁:
                lock.release()
    
    
    if __name__ == "__main__":
        t1 = threading.Thread(target=run_thread, args=(5,))
        t2 = threading.Thread(target=run_thread, args=(8,))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(balance)

    当多个线程同时执行lock.acquire()时,只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止。

    获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程。所以我们用try...finally来确保锁一定会被释放。

    2、threading.Rlock()

     RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁。

    import threading
    
    # Lock对象
    lock = threading.Lock()
    
    def test1():
        lock.acquire()
        lock.acquire()
        # 产生了死琐。
        print("test1")
        lock.release()
        lock.release()
    
    # RLock对象
    rLock = threading.RLock()
    
    def test2():
        rLock.acquire()
        rLock.acquire()
        # 在同一线程内,程序不会堵塞。
        print("test2")
        rLock.release()
        rLock.release()
    
    
    
    if __name__ == "__main__":
        t1 = threading.Thread(target=test1, args=())
        t2 = threading.Thread(target=test2, args=())
        t1.start()
        t2.start()
    
        t2.join()
        t1.join()

    RLock允许嵌套。

    def run1():
        print("grab the first part data")
        lock.acquire()
        global num
        num +=1
        lock.release()
        return num
    def run2(): print("grab the second part data") lock.acquire() global num2 num2+=1 lock.release() return num2
    def run3(): lock.acquire() res = run1() print('--------between run1 and run2-----') res2 = run2() lock.release() print(res,res2)

      = threading.Thread(target=run3)
      t.start()

    3. threading.active_count() 返回当前存活的线程对象的数量

    通过计算len(threading.enumerate())长度而来

    4. threading.current_thread() 返回当前线程对象

    import time
    import threading
    
    def run():
        thread = threading.current_thread()
        print('%s is running...'% thread.getName())    #返回线程名称
        time.sleep(10)    #休眠10S方便统计存活线程数量
    
    if __name__ == "__main__":
        #设置thread的名称
        t = threading.Thread(target=run, name="test_thread")
        t.start()
    
        print('%s is running...' % threading.current_thread().getName())
        print("thread count:%d" % threading.active_count())
        print("thread count:%d" % len(threading.enumerate()))
    
        t.join()

    5. threading.enumerate()返回当前存在的所有线程对象的列表

    6.threading.get_ident() 返回线程pid

    7. threading.main_thread()

    import time
    import threading
    
    def run():
        print("get the main_thread name is %s" % threading.main_thread().getName())
        print("pid:%s" % threading.get_ident())
        print('ThreadName is :%s' % threading.enumerate())  # 返回所有线程对象列表
        time.sleep(10)
    
    if __name__ == "__main__":
        #设置thread的名称
        t = threading.Thread(target=run, name="test_thread")
        t.start()
    
        t.join()

    8. threading.Condition()

    可以把Condiftion理解为一把高级的锁,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。

    threadiong.Condition在内部维护一个锁对象(默认是RLock,可被多次acquire),可以在创建Condigtion对象的时候把锁对象作为参数传入。

    Condition也提供了acquire, release方法,其含义与锁的acquire, release方法一致,其实它只是简单的调用内部锁对象的对应的方法而已。

    Condition还提供wait方法、notify方法、notifyAll方法(特别要注意:这些方法只有在占用锁(acquire)之后才能调用,否则将会报RuntimeError异常。)

    wait([timeout]):线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。

    wait()必须在已获得锁前提下才能调用,否则会触发RuntimeError。调用wait()会释放锁,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得锁.

     notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。

    notify()必须在已获得锁前提下才能调用,否则会触发RuntimeError。notify()不会主动释放锁。

     notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)(不知道是否会产生线程惊群

    捉迷藏的游戏:

    一个藏(Hider),一个找(Seeker)

    戏的规则如下:

    cond = threading.Condition()

    1. 游戏开始之后,Seeker加锁cond.acquire(),蒙上眼睛后 cond.notify() 通知Hider已经蒙眼,

    2. 游戏开始之后,Hider加锁cond.acquire(),cond.wait() 等待Seeker的通知(已经蒙眼),

    3. Hider收到Seeker蒙眼通知之后,进行躲藏,在完成躲藏之后cond.notify()通知Seeker已经躲藏好,并cond.wait()等待Seeker找到他的通知

    4、Seeker接收到通知(Hider完成躲藏)之后,就开始找Hider,并在找到Hider向Hider发出通知cond.notify()

    问题!!!如果超过1分钟没有找到躲藏者,判Seeker输,怎么弄?

    尝试,cond.wait(60) 加上使用一个全局bool类型的值,结果发现cond.wait(60)在超时之后并不会唤醒,不知道是什么原因,我的测试环境是Windows

    import time
    import threading
    
    def Seeker(cond, name):
        time.sleep(2)
        cond.acquire()#可多次acquire
        print('%s :我已经把眼睛蒙上了!'% name)
        cond.notify()
        cond.wait()
        for i in range(3):
            print('%s is finding!!!'% name)
            time.sleep(2)
        print("yeah, find the hider")
        cond.notify()
        cond.release()
        print('%s :我赢了!'% name)
    
    def Hider(cond, name):
        cond.acquire()
        cond.wait()
        for i in range(2):
            print('%s is hiding!!!'% name)
            time.sleep(3)
        print('%s :我已经藏好了,你快来找我吧!'% name)
        cond.notify()
        cond.wait()
        cond.release()
        print('%s :被你找到了,唉~^~!'% name)
    
    if __name__ == "__main__":
        cond = threading.Condition()
        seeker = threading.Thread(target=Seeker, args=(cond, 'seeker'))
        hider = threading.Thread(target=Hider, args=(cond, 'hider'))
        seeker.start()
        time.sleep(0.1)
        hider.start()

    9. threading.Semaphore和BoundedSemaphore

    Semaphore:Semaphore 在内部管理着一个计数器。

    调用 acquire() 会使这个计数器 -1,release() 则是+1(可以多次release(),所以计数器的值理论上可以无限).计数器的值永远不会小于 0,当计数器到 0 时,再调用 acquire() 就会阻塞,直到其他线程来调用release()

     BoundedSemaphore:类似于Semaphore;不同在于BoundedSemaphore 会检查内部计数器的值,并保证它不会大于初始值,如果超了,就引发一个 ValueError。

    多数情况下,semaphore 用于守护限制访问(但不限于 1)的资源,如果 semaphore 被 release() 过多次,这意味着存在 bug

    import time
    import threading
    
    def run(n):
        # 获得信号量,信号量减一
        semaphore.acquire()
        time.sleep(1)
        print("run the thread: %s" % n)
    
        # 释放信号量,信号量加一
        semaphore.release()
        #semaphore.release()    # 可以多次释放信号量,每次释放计数器+1
        #semaphore.release()    # 可以多次释放信号量,每次释放计数器+1
    
    
    
    if __name__ == "__main__":
        semaphore = threading.Semaphore(2)#semaphore计数器初始化为2
    
        for i in range(10):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    
        while threading.active_count() != 1:
            time.sleep(0.1)
        else:
            print('----all threads done---')
    
        print("----------main thread finish-----------")
    import time
    import threading
    
    
    def run(n):
        # 获得信号量,信号量减一
        semaphore.acquire()
        time.sleep(1)
        print("run the thread: %s" % n)
    
        # 释放信号量,信号量加一
        try:
            semaphore.release()
        except ValueError as e:
            print(e)
    
    
    
    if __name__ == "__main__":
        semaphore = threading.BoundedSemaphore(2)#内部计数器的初始值,后续操作不允许计数器超过初始值
    
        for i in range(10):
            t = threading.Thread(target=run, args=(i,))
            t.start()
    
        while threading.active_count() != 1:
            time.sleep(0.1)
        else:
            print('----all threads done---')
    
        print("----------main thread finish-----------")
  • 相关阅读:
    NGINX
    nginx修改上传文件大小限制
    Mysql主从复制机制原理
    MongoDB系列---用户及权限管理02
    MongoDB系列---入门安装操作01
    浅谈原理--hashCode方法
    ActiveMQ学习总结------原生实战操作(下)03
    dubbo配置负载均衡、集群环境
    ActiveMQ学习总结------入门篇01
    vsftpd上传文件大小为0(主动模式)
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/9270232.html
Copyright © 2020-2023  润新知