zoukankan      html  css  js  c++  java
  • day33 GIL锁 线程队列 线程池

    1.    全局解释器锁GIL

    Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
      对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。

      在多线程环境中,Python 虚拟机按以下方式执行:

      a、设置 GIL;

      b、切换到一个线程去运行;

      c、运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));

      d、把线程设置为睡眠状态;

      e、解锁 GIL;

      d、再次重复以上所有步骤。
      在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。

    2.   线程队列

    queue队列 :使用import queue,用法与进程Queue一样

    queue is especially useful in threaded programming when information must be exchanged safely between multiple threads.

    class queue.Queue(maxsize=0) #先进先出
    import queue
    #先进先出型
    q=queue.Queue(3)
    q.put(3)
    q.put(2)
    q.put(1)
    
    print(q.get())
    print(q.get())
    print(q.get())
    
    """
    结果
    3
    2
    1
    """
    先进先出型

    class queue.LifoQueue(maxsize=0) #last in fisrt out

    import queue
    
    q=queue.LifoQueue()
    q.put(1)
    q.put(2)
    q.put(3)
    
    print(q.get())
    print(q.get())
    print(q.get())
    """
    结果
    3
    2
    1
    
    """
    先进后出行

     class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

    import queue
    
    q=queue.PriorityQueue()
    #put进入一个元组,元组的第一个元素一般是优先级(一般是数字,也可以是非数字),数字越小,优先级越小
    q.put((-1,"a"))
    q.put((0,"b"))
    q.put((10,"c"))
    q.put((20,"d"))
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get())
    
    """
    结果
    数字越小,优先级越高,越优先输出
    (-1, 'a')
    (0, 'b')
    (10, 'c')
    (20, 'd')
    
    
    """
    优先级队列

    或者

    import queue
    
    
    class A:
        def __init__(self, property, value):
            self.property = property
            self.value = value
    
        def __lt__(self, other):
            return self.property < other.property
    
    
    a = A(1, 'a')
    b = A(2, 'b')
    c = A(3, 'aaaaa')
    d = A(1, 'bbbb')
    
    q = queue.PriorityQueue()
    q.put(a)
    q.put(b)
    q.put(c)
    q.put(d)
    
    print(q.get().value)
    print(q.get().value)
    print(q.get().value)
    print(q.get().value)
    
    
    #############
    a
    bbbb
    b
    aaaaa

    注:优先级相同的会根据第二元素比较,第二个元素是根据编码的顺序比较,并且第二个元素的类型必须一致并且,是有序的才可以比较

    如果两个值的优先级一样,那么按照后面的值的acsii码顺序来排序,如果字符串第一个数元素相同,比较第二个元素的acsii码顺序

    TypeError: unorderable types: dict() < dict() 不能是字典

    优先级相同的两个数据,他们后面的值必须是相同的数据类型才能比较,可以是元祖,也是通过元素的ascii码顺序来排序

    3.    Python标准模块--concurrent.futures

    #1 介绍
    concurrent.futures模块提供了高度封装的异步调用接口
    ThreadPoolExecutor:线程池,提供异步调用
    ProcessPoolExecutor: 进程池,提供异步调用
    Both implement the same interface, which is defined by the abstract Executor class.
    
    #2 基本方法
    #submit(fn, *args, **kwargs)
    异步提交任务
    
    #map(func, *iterables, timeout=None, chunksize=1) 
    取代for循环submit的操作
    
    #shutdown(wait=True) 
    相当于进程池的pool.close()+pool.join()操作
    wait=True,等待池内所有任务执行完毕回收完资源后才继续
    wait=False,立即返回,并不会等待池内的任务执行完毕
    但不管wait参数为何值,整个程序都会等到所有任务执行完毕
    submit和map必须在shutdown之前
    
    #result(timeout=None)
    取得结果
    
    #add_done_callback(fn)
    回调函数
    import time,random
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    
    def func(n):
        time.sleep(random.randint(1,3))
        return n*n
    
    
    if __name__ == '__main__':
        p=ProcessPoolExecutor(max_workers=4)
        list=[]
        for i in range(10):
            ret=p.submit(func,i)
            list.append(ret)
            print(ret.result())
        p.shutdown()
        for ret in list:
            print(ret.result())
    from concurrent.futures import ThreadPoolExecutor
    
    def func(n):
        return n**2
    
    if __name__ == '__main__':
        t_p=ThreadPoolExecutor(max_workers=4)
        list=[]
        for i in range(10):
            ret=t_p.submit(func,i)#异步提交任务
            list.append(ret)
            # print(ret.result())   #等待任务提交之后拿去结果,拿不到就柱塞,拿到了就继续
    
        t_p.shutdown()
        print("主进程结束")
        for ret in list:
            print(ret.result())
        
    ThreadPoolExecutor
    from concurrent.futures import ThreadPoolExecutor
    
    
    def func(n):
        return n*n
    if __name__ == '__main__':
        t_p=ThreadPoolExecutor(max_workers=4)
    
        # for i in range(10):
        #     t_p.submit(func,i)
        t_p.map(func,range(10))  #map取代了for+submit
    map的用法
    from concurrent.futures import ThreadPoolExecutor
    
    def get(n):
        return n*n
    def call(m):
        print(">>",m)
        print(m.result())
    
    if __name__ == '__main__':
        t_p=ThreadPoolExecutor(max_workers=4)
    
        for i in range(3):
            t_p.submit(get,i).add_done_callback(call)
            
    """
    结果
    >> <Future at 0x294c1d0 state=finished returned int> #必须.result才能拿到结果
    0
    >> <Future at 0x294c1d0 state=finished returned int>
    1
    >> <Future at 0x294c1d0 state=finished returned int>
    4
    """
  • 相关阅读:
    vue中watch的详细用法
    Golang实现请求限流的几种办法
    观察者模式
    原创-阿里云上SLB暴露K8S服务-四层协议/七层协议
    K8S-HPA创建指南
    阿里云k8s-nas挂载指南
    非原创--mysql语言分类
    mysql命令
    MongoDB从节点支持读请求
    MongoDB用户权限管理
  • 原文地址:https://www.cnblogs.com/tjp40922/p/10058859.html
Copyright © 2011-2022 走看看