1、Barrier
# Barrier 可以理解为路障或者道闸;
# 作用:等待所有的线程到齐后开始放行;
broken 如果屏障状态处于被打破的状态,返回True;
abort() 将屏障置于broken状态,等待中的线程或者调用等待方法的线程中都会抛出BrokenBarrierError异常,等待中的线程无效,不会被计入参与方直到屏障被reset;
reset() 恢复屏障;重新开始拦截;
# 实例代码:
from threading importThread, Lock, RLock, Event, Condition, Barrierimportthreadingimporttimeimportloggingimportrandom
FORMAT= "%(asctime)-15s\t [%(threadName)s %(thread)8d] %(message)s"logging.basicConfig(level=10, format=FORMAT)
barrier= Barrier(3)defworker(barrier: Barrier):
logging.info('waiting for {} threads'.format(barrier.n_waiting))try:
barrier_id=barrier.wait()
logging.info('after barrier {}'.format(barrier_id))exceptthreading.BrokenBarrierError:
logging.info('Broken Barrier. run')for i in range(1,6):if i == 2:
barrier.abort()elif i == 3:
barrier.reset()
threading.Event().wait(1)
threading.Thread(target=worker,name='worker-{}'.format(i),args=(barrier,)).start()print(i,barrier.n_waiting)'''
运行结果分析:1 1 # 等待中的线程为1
2018-11-06 16:52:10,256 [worker-1 3620] waiting for 0 threads
2018-11-06 16:52:10,257 [worker-1 3620] Broken Barrier. run
2018-11-06 16:52:11,257 [worker-2 5800] waiting for 0 threads
2018-11-06 16:52:11,257 [worker-2 5800] Broken Barrier. run
2 0 # i=2的时候由于barrier被打破,则等待的线程无效,不会被计入wait参与方;
2018-11-06 16:52:12,258 [worker-3 5956] waiting for 0 threads
3 1 # i=3的时候barrier被修复,线程从新被计入wait方法
4 2
2018-11-06 16:52:13,259 [worker-4 7612] waiting for 1 threads
2018-11-06 16:52:14,259 [worker-5 10012] waiting for 2 threads
5 0 # i=5的时候 参与方线程为3,4,5 达到barrier放行的数目,所有线程都放行,所以等待线程为0
2018-11-06 16:52:14,260 [worker-5 10012] after barrier 2
2018-11-06 16:52:14,260 [worker-4 7612] after barrier 1
2018-11-06 16:52:14,260 [worker-3 5956] after barrier 0'''
2、semaphore
# semaphore 信号量与Lock类似,信号量对象内部维护一个倒计数器,每一次acquire都会减1,当acquire方法发现计数器为0,就阻塞请求的线程,直到其他线程对信号量release后,计数器大于1,恢复阻塞线程;
# 由于semapore对于release归还越界问题没有限制,则会出现不可预期的效果,所有为了安全则一般使用BoundedSemaphore类;
#BoundedSemaphore类: 有界的信号量,不允许release超出初始值的范围,否则,抛出ValueError异常;
# 信号量一般用于连接池,实例代码
classConn:def __init__(self,name):
self.name=namedef __repr__(self):returnstr(self.name)classPool:def __init__(self,count:int):
self.count=count
self.pool=[self._connect("conn-{}".format(x)) for x inrange(self.count)]
self.sem=BoundedSemaphore(count)def_connect(self,conn_name):returnConn(conn_name)defget_conn(self):
self.sem.acquire()returnself.pool.pop()defreturn_conn(self,conn:Conn):
self.pool.append(conn)
self.sem.release()
p=Pool(5)print(p.pool)'''[conn-0, conn-1, conn-2, conn-3, conn-4]'''
3、数据结构与GIL
(1)什么是GIL?
# GIL 全局解释器锁;
# 由于python是一种解释性语言,则需要经过解释器将py代码编译成cpu能识别的字节码,所有就有了python解释器的存在,例如 Jpython,Cpython,PyPy等解释器;
# 由于Cpython已经成为Python的实际标准,而提到GIL一般指的是Cpython,Cpython设置GIL的主要原因是为了保证不让多线程同时执行一条字节码,这就避免了可能多个线程对同一个对象进行操作;
# 保留GIL的原因:降低学习难度,移除GIL会降低Cpython单线程的执行效率;
(2)python统一进程内多线程的工作流程
①:拿到公共数据;
②:申请GIL;
③:Python解释器调用操作系统原生线程
④:cpu执行运算
⑤:当该线程执行一段时间消耗完,无论任务是否已经执行完毕,都会释放GIL
⑥:下一个被CPU调度的线程重复上面的过程;