信号量(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

猜你喜欢

转载自www.cnblogs.com/guyexiangyun/p/10589621.html