多线程开发 使用Semaphore和BoundedSemaphore对象

发布时间 2023-07-18 16:28:16作者: super-ma

多线程开发 使用Semaphore和BoundedSemaphore对象

一、使用Semaphore和BoundedSemaphore对象

在Python中,可以使用Semaphore和BoundedSemaphore来控制多线程信号系统中的计数器。

1. Semaphore

在Python程序中,类threading.Semaphore是一个信号机,控制着对公共资源或者临界区的访问。信号机维护有一个计数器,指定可同时访问资源或者进入临界区的线程数。每次有一个线程获得信亏机时,计数器为-1。若计数器为0,其他线程就停止访问信号机,,直到另一个线程释放信号机。

在对象 Semaphore中,主要包含了如下所示的内置方法:

(1) aquire(blocking = True,timeout = None): 用于获取Semaphore对象。

  • 当使用默认参数(blocking = True)调用本方法时,如果内部计数器的值大于零,将之减一,并返回;如果等于零,则阻塞,并等待其他线程调用release()方法以使计数器为正。这个过程有严格的互锁机制控制,以保证如果有多条线程正在等待解锁,release()调用只会唤醒其中一条线程。唤醒哪一条是随机的。本方法返回True,或无限阻塞。
  • 如果blocking = False,则不阻寒,但若获取失败的话,返回False。
  • 当设定了timeout参数时,最多阻塞timeout秒,如果超时,返回False。

(2) release():用于释放Semaphore,给内部计数器加1,可以唤醒处于等待状态的线程。

  • 在使用计数器对象Semaphore时,调用acquire()会使这个计数器减1,调用release()会使这个计数器加1。
  • 计数器的值永远不会小于0,当计数器到0时,再调用acquire()就会阻塞,直到其他线程来调用release()为止。

例如在下面的实例中,演示了使用Semaphore对象运行4个线程的过程。

import threading
import time


def func(semaphore: threading.Semaphore, num):
    # 获得信号量,信号量 -1
    semaphore.acquire()
    print(f"打印信号量:第{num}次")
    time.sleep(3)

    # 释放信号量,信号量 +1
    semaphore.release()


if __name__ == '__main__':
    # 初始化信号量,数量为 2
    semaphore = threading.Semaphore(2)
    # 运行4个线程
    for num in range(4):
        t = threading.Thread(target=func, args=(semaphore, num))
        t.start()

2. BoundedSemaphore

在pyhon程序中,类threading.BoundSemaphore用于实现BoundedSemaphore对象。BoundedSemaphore会检查内部计数器的值,并保证它不会大于初始值,如果超过就会引发一个ValueError错误。在大多数情况下,BoundedSemaphore用于守护限制访问(
但不限于1)的资源,如果semaphore被release()过多次,这意味着存在在bug。

对象BoundedSemaphore会返回一个新的有界信号量对象,一个有界信号量会确保它当前的值不超过它的初始值。如果超过,则引发ValueError,在大部分情况下,信号量用于守护有限容量的资源。如果信号量被释放太多次,它是一种有bug的迹象,如果没有给出,value默认为1。

例如在下面的实例中,演示了使用BoundedSemaphore对象运行4个线程的过程。

import threading
import time


def fun(semaphore, num):
  # 获得信号量,信号量减一
  semaphore.acquire()
  print("thread %d is running." % num)
  time.sleep(3)
  # 释放信号量,信号量加一
  semaphore.release()
  # 再次释放信号量,信号量加一,这是超过限定的信号量数目,这时会报错VleE: Semaphore releaged too manytimes
  semaphore.release()


if __name__ == '__main__':
  # 初始化信号量,教量为2,最多有2个线程获得信号量,信号量不能通过释放而大于2
  semaphore = threading.BoundedSemaphore(2)
  # 运行4个线程
  for num in range(4):
    t = threading.Thread(target=fun, args=(semaphore, num))
    t.start()

文章来源:https://blog.csdn.net/weixin_47021806/article/details/115535520