python线程同步理解_Python学习线程间同步之二

1、Barrier

# Barrier 可以理解为路障或者道闸;

# 作用:等待所有的线程到齐后开始放行;

c4aa189c77d3f2cd650b2ea4f0cc834c.png

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,恢复阻塞线程;

18e20995aa2724790efc8641778c46be.png

# 由于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调度的线程重复上面的过程;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值