PS:Lock、Condition、Semaphore都支持上下文协议,内部enter和exit方法都是使用的acquire和release方法 就是都支持:with 语法
主要是提供一个有限的线程池空间,给每个一个线程分配一个锁,机制,当线程调度执行完成,让出自身持有的锁,分给其他等待的线程。
PS:意思就是:在创建多线程的时候,限制同一时间最多运行N个线程。避免无线创建线程。
semaphore信号量内部存在一个计数器,用于记录当前线程的数量计数,
class Semaphore:
"""This class implements semaphore objects.
Semaphores manage a counter representing the number of release() calls minus
the number of acquire() calls, plus an initial value. The acquire() method
blocks if necessary until it can return without making the counter
negative. If not given, value defaults to 1.
"""
# After Tim Peters' semaphore class, but not quite the same (no maximum)
def __init__(self, value=1):
if value < 0:
raise ValueError("semaphore initial value must be >= 0")
self._cond = Condition(Lock())
self._value = value
def acquire(self, blocking=True, timeout=None):
"""Acquire a semaphore, decrementing the internal counter by one.
When invoked without arguments: if the internal counter is larger than
zero on entry, decrement it by one and return immediately. If it is zero
on entry, block, waiting until some other thread has called release() to
make it larger than zero. This is done with proper interlocking so that
if multiple acquire() calls are blocked, release() will wake exactly one
of them up. The implementation may pick one at random, so the order in
which blocked threads are awakened should not be relied on. There is no
return value in this case.
When invoked with blocking set to true, do the same thing as when called
without arguments, and return true.
When invoked with blocking set to false, do not block. If a call without
an argument would block, return false immediately; otherwise, do the
same thing as when called without arguments, and return true.
When invoked with a timeout other than None, it will block for at
most timeout seconds. If acquire does not complete successfully in
that interval, return false. Return true otherwise.
"""
if not blocking and timeout is not None:
raise ValueError("can't specify timeout for non-blocking acquire")
rc = False
endtime = None
with self._cond:
while self._value == 0:
if not blocking:
break
if timeout is not None:
if endtime is None:
endtime = _time() + timeout
else:
timeout = endtime - _time()
if timeout <= 0:
break
self._cond.wait(timeout)
else:
self._value -= 1
rc = True
return rc
__enter__ = acquire
def release(self):
"""Release a semaphore, incrementing the internal counter by one.
When the counter is zero on entry and another thread is waiting for it
to become larger than zero again, wake up that thread.
"""
with self._cond:
self._value += 1
self._cond.notify()
def __exit__(self, t, v, tb):
self.release()
从源码中可以看到,信号量,使用我们的条件变量来进行相关的线程的通知和唤醒的机制。
相同的地方:
区别:
同一个时间内只运行运行三个线程:
from threading import Thread, BoundedSemaphore
from time import time, sleep
import threading
def execute(i):
start = time()
with sem:
end = time()
print("线程ID: {0}, 名字{1}等待事件:{2}".format(threading.get_ident(),threading.current_thread().getName(),end - start))
sleep(2)
sem = BoundedSemaphore(3) # 控制同一时刻最多允许三个线程访问资源
for i in range(12):
Thread(target=execute,name="我是线程:%s"%(i),args=(i,)).start()
输出结果:
线程ID: 31384, 名字我是线程:0等待事件:0.0
线程ID: 9152, 名字我是线程:1等待事件:0.0
线程ID: 31220, 名字我是线程:2等待事件:0.0
线程ID: 26436, 名字我是线程:3等待事件:2.002983331680298
线程ID: 22184, 名字我是线程:5等待事件:2.002983331680298
线程ID: 32456, 名字我是线程:4等待事件:2.002983331680298
线程ID: 30844, 名字我是线程:6等待事件:4.0141541957855225
线程ID: 14732, 名字我是线程:7等待事件:4.013157606124878
线程ID: 22176, 名字我是线程:8等待事件:4.013157606124878
线程ID: 23556, 名字我是线程:9等待事件:6.024932622909546
线程ID: 30632, 名字我是线程:11等待事件:6.024932622909546
线程ID: 21276, 名字我是线程:10等待事件:6.024932622909546
个人其他博客地址
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。 2:关于文章内容,有部分内容参考自互联网整理,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。