• 信号量(Semaphore)


    在python的多线程体系中,一共有4种锁:

    • 同步锁(互斥锁):Lock;
    • 递归锁:RLock;
    • 信号量:Semaphore;
    • 同步条件锁:Condition.

    信号量(semaphore)是一种可以控制线程并发数的锁,也就是控制同一时刻有多少线程可以获取内存资源。信号量通过内部计数器来控制线程的进入和执行,实例属性value用来设置计数器的大小(默认为1)。这就好比在一个地方有10个停车位(value=10),同时可以停10辆车;当第11辆车过来时,需要等待其他车辆把停车位让出来。信号量相当于批量给线程加锁,Lock和RLock都是给一个线程加锁,而我们实例化一个信号量后,就可以给多个线程加锁,保证同一时刻多个线程在执行(其实是来回切换)。

    Semaphore内部也定义了acquire()和release()两个方法。当调用acquire()方法时内部计数器减1,有线程获取了执行权;调用release()方法时计数器加1,有线程释放了执行权,其他线程就可以进入执行。当计数器的值等于0时,acquire()方法会阻塞线程的执行,直到有线程调用release()方法后使该计数器的值大于0。

    • acquire(blocking=True, timeout=None):当使用默认参数调用该方法时,如果内部计数器大于1,将其减1。
      • 第一个参数blocking,默认为True,即当计数器(value值)为0时阻塞线程进入执行,直到有其他线程调用release()方法将计数器设置到大于0,这个过程有严格的联锁控制,以保证如果有多条线程正在等待解锁,release() 调用只会唤醒其中一条线程(随机唤醒)。此时这个方法返回True,或无限阻塞;如果blocking=False,则不阻塞线程的执行,但是这种情况下其他线程获取执行失败,此时acquire方法返回False。
      • 第二参数timeout,设置最多阻塞多少秒,如果超时(即在这段时间内线程并未获取执行权),就会返回False。
    • release():没有参数,调用该方法时,使内部计数器加1(释放某个线程,允许其他等待线程进入执行)。

    示例1:当调用默认参数的acquire方法时:

     1 import threading, time
     2 
     3 
     4 class MyThread(threading.Thread):
     5 
     6     def run(self):
     7         get_flag = semaphore.acquire() # 线程获取执行权
     8         print("get_flag(before if)--->", get_flag) # 打印acquire()方法的返回值
     9         if get_flag:
    10             print(self.name, "...at ", time.ctime())
    11             time.sleep(3) # 每个线程执行3秒
    12             print("%s has done... at %s" % (self.name, time.ctime()))
    13             semaphore.release()
    14 
    15 
    16 if __name__ == "__main__":
    17 
    18     semaphore = threading.Semaphore(2) # 容量为2,每次允许2个线程执行
    19 
    20     threads = []
    21 
    22     for i in range(10): # 创建10个线程实例
    23         threads.append(MyThread())
    24 
    25     for t in threads:
    26         t.start()

     打印结果如下:

    get_flag(before if)---> True
    Thread-1 ...at  Mon Mar 25 10:51:21 2019
    get_flag(before if)---> True
    Thread-2 ...at  Mon Mar 25 10:51:21 2019
    Thread-2 has done... at Mon Mar 25 10:51:24 2019
    get_flag(before if)---> True
    Thread-1 has done... at Mon Mar 25 10:51:24 2019
    Thread-3 ...at  Mon Mar 25 10:51:24 2019
    get_flag(before if)---> True
    Thread-4 ...at  Mon Mar 25 10:51:24 2019
    Thread-4 has done... at Mon Mar 25 10:51:27 2019
    Thread-3 has done... at Mon Mar 25 10:51:27 2019
    get_flag(before if)---> True
    get_flag(before if)---> True
    Thread-6 ...at  Mon Mar 25 10:51:27 2019
    Thread-5 ...at  Mon Mar 25 10:51:27 2019
    Thread-5 has done... at Mon Mar 25 10:51:30 2019
    Thread-6 has done... at Mon Mar 25 10:51:30 2019
    get_flag(before if)---> True
    get_flag(before if)---> True
    Thread-7 ...at  Mon Mar 25 10:51:30 2019
    Thread-8 ...at  Mon Mar 25 10:51:30 2019
    Thread-7 has done... at Mon Mar 25 10:51:33 2019
    Thread-8 has done... at Mon Mar 25 10:51:33 2019
    get_flag(before if)---> True
    get_flag(before if)---> True
    Thread-9 ...at  Mon Mar 25 10:51:33 2019
    Thread-10 ...at  Mon Mar 25 10:51:33 2019
    Thread-10 has done... at Mon Mar 25 10:51:36 2019
    Thread-9 has done... at Mon Mar 25 10:51:36 2019
    
    Process finished with exit code 0

    可以看到,当使用默认blocking=True时,每个线程都成功地获取了执行权。每次允许2个线程执行,其他线程会被阻塞,等待被执行的线程释放执行权后,其他线程再进入执行。

    示例2:当blocking=False时

     1 import threading, time
     2 
     3 
     4 class MyThread(threading.Thread):
     5 
     6     def run(self):
     7         get_flag = semaphore.acquire(blocking=False)
     8         print("get_flag(before if)--->", get_flag)
     9         if get_flag:
    10             print(self.name, "...at ", time.ctime())
    11             time.sleep(3)
    12             print("%s has done... at %s" % (self.name, time.ctime()))
    13             semaphore.release()
    14 
    15 
    16 if __name__ == "__main__":
    17 
    18     semaphore = threading.Semaphore(2)
    19 
    20     threads = []
    21 
    22     for i in range(10):
    23         threads.append(MyThread())
    24 
    25     for t in threads:
    26         t.start()

    打印结果:

    get_flag(before if)---> True
    Thread-1 ...at  Mon Mar 25 10:57:27 2019
    get_flag(before if)---> True
    Thread-2 ...at  Mon Mar 25 10:57:27 2019
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    get_flag(before if)---> False
    Thread-2 has done... at Mon Mar 25 10:57:30 2019
    Thread-1 has done... at Mon Mar 25 10:57:30 2019
    
    Process finished with exit code 0

    可以看到,第一批的线程获取了执行权;但是其他线程并没有被阻塞(blocking=False),所以它们也会去争取执行权,但是获取失败,acquire()方法返回了False。即便线程释放了执行权,其他线程也不再去争取了。所有线程就会在第一批线程执行结束后退出。

    参考:

    http://www.cnblogs.com/yuanchenqi/articles/6248025.html

    https://blog.csdn.net/asdasdasd123123123/article/details/84139000

  • 相关阅读:
    前端周刊第一期
    Java CAS 原理详解
    【转载】Linux系统调用SYSCALL_DEFINE详解
    简述伪共享和缓存一致性MESI
    exchange发邮件
    Flutter屏幕适配(自适应)方案
    dart类初始化 future方案
    windows下postgresql自启动
    How can I call an async method in StatelessWidget.build method?
    实战分层架构
  • 原文地址:https://www.cnblogs.com/guyexiangyun/p/10589621.html
Copyright © 2020-2023  润新知