zoukankan      html  css  js  c++  java
  • Python学习线程间同步之二

    1、Barrier

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

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

    broken    如果屏障状态处于被打破的状态,返回True;
    abort()    将屏障置于broken状态,等待中的线程或者调用等待方法的线程中都会抛出BrokenBarrierError异常,等待中的线程无效,不会被计入参与方直到屏障被reset;
    reset()    恢复屏障;重新开始拦截;

    # 实例代码:

    from threading import Thread, Lock, RLock, Event, Condition, Barrier
    import threading
    import time
    import logging
    import random
    FORMAT = "%(asctime)-15s	 [%(threadName)s %(thread)8d] %(message)s"
    logging.basicConfig(level=10, format=FORMAT)
    barrier = Barrier(3)
    
    def worker(barrier: Barrier):
        logging.info('waiting for {} threads '.format(barrier.n_waiting))
        try:
            barrier_id=barrier.wait()
            logging.info('after barrier {}'.format(barrier_id))
        except threading.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异常;

    # 信号量一般用于连接池,实例代码

    class Conn:
        def __init__(self,name):
            self.name=name
    
        def __repr__(self):
            return str(self.name)
    
    class Pool:
        def __init__(self,count:int):
            self.count=count
            self.pool=[self._connect("conn-{}".format(x)) for x in range(self.count)]
            self.sem=BoundedSemaphore(count)
    
        def _connect(self,conn_name):
            return Conn(conn_name)
    
        def get_conn(self):
            self.sem.acquire()
            return self.pool.pop()
    
        def return_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调度的线程重复上面的过程;

  • 相关阅读:
    mysql登录和连接 权限
    No package mysql-server available.
    rails开发demo(一)搭建环境
    chrome和搜狗浏览器的js问题
    setInterval setTimeout clearInterval
    几道面试题
    du df 查看文件和文件夹大小
    win7开启休眠功能
    ssh key scp命令 scp无密码传输
    dd 生成指定大小文件
  • 原文地址:https://www.cnblogs.com/soulgou123/p/9891315.html
Copyright © 2011-2022 走看看