zoukankan      html  css  js  c++  java
  • python 并发 GIL锁 锁 线程池 生产者消费模型

    python的GIL 锁

      python内置的一个全局解释器锁 , 锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度

    为什么有这把GIL锁?

      python语言的创始人在开发这门语言时 , 目的快速把语言开发出来 , 如果加上GIL锁(C语言加锁) , 切换时按照100条字节指令来进行线程间的切换

    锁 : 

      1.锁 : Lock(1次放1个)

        线程安全 , 多线程操作时 , 内部会让所有线程排队处理 , 如 : list / dict / Queue

        线程不安全 + 人  =>排队处理

        需求:

          a:创建100个进程 ,   在列表中追加8

          b:创建100个线程

            v = []

            锁

            把自己添加到列表中

            在读取列表的最后一个

            解锁

    import threading
    import time
    
    v = []
    lock = threading.Lock()
    
    def func(arg):
        lock.acquire()
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()

      2.锁 : RLock(1次放1个)

    import threading
    import time
    
    v = []
    lock = threading.RLock()
    def func(arg):
        lock.acquire()
        lock.acquire()
    
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
    
        lock.release()
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()

      3锁 : BoundedSemaphore (1次放N个) 信号量

    import time
    import threading
    
    lock = threading.BoundedSemaphore(3)
    def func(arg):
        lock.acquire()
        print(arg)
        time.sleep(1)
        lock.release()
    
    
    for i in range(20):
        t =threading.Thread(target=func,args=(i,))
        t.start()

      4.锁 : Condition (1次方法x个)

    import time
    import threading
    
    lock = threading.Condition()
    
    
    def func(arg):
        print('线程进来了')
        lock.acquire()
        lock.wait() # 加锁
    
        print(arg)
        time.sleep(1)
    
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    while True:
        inp = int(input('>>>'))
    
        lock.acquire()
        lock.notify(inp)
        lock.release()

      5.锁 : Event(1次放所有)

     

    import time
    import threading
    
    lock = threading.Event()
    
    
    def func(arg):
        print('线程来了')
        lock.wait() # 加锁:红灯
        print(arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set() # 绿灯
    
    
    lock.clear() # 再次变红灯
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set()

    以上例子 :  线程安全 , 列表和字典线程安全

        为什么要加锁?

          非线程安全

          控制一段代码

     6. threading.local

        作用 : 内部自动会为每个线程维护一个空间(字典) 用于当前存取属于自己的值 , 保证线程之间的数据隔离

          

          {
            线程ID: {...}
            线程ID: {...}
            线程ID: {...}
            线程ID: {...}
          }

    import time
    import threading
    
    v = threading.local()
    
    def func(arg):
        # 内部会为当前线程创建一个空间用于存储:phone=自己的值
        v.phone = arg
        time.sleep(2)
        print(v.phone,arg) # 去当前线程自己空间取值
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()

    原理方法如下

    import time
    import threading
    
    DATA_DICT = {}
    
    def func(arg):
        ident = threading.get_ident()
        DATA_DICT[ident] = arg
        time.sleep(1)
        print(DATA_DICT[ident],arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()

    7. 线程池

    from concurrent.futures import ThreadPoolExecutor
    import time
    
    def task(a1,a2):
        time.sleep(2)
        print(a1,a2)
    
    # 创建了一个线程池(最多5个线程)
    pool = ThreadPoolExecutor(5)
    
    for i in range(40):
        # 去线程池中申请一个线程,让线程执行task函数。
        pool.submit(task,i,8)

    8.生产者消费者模型

      三部件 : 

          生产者

              队列 ,   先进先出

              扩展 : 栈  ,  后进先出

          消费者

      问 : 生产者消费者模型解决了啥问题?   不用一直等待问题

    import time
    import queue
    import threading
    q = queue.Queue() # 线程安全
    
    def producer(id):
        """
        生产者
        :return:
        """
        while True:
            time.sleep(2)
            q.put('包子')
            print('厨师%s 生产了一个包子' %id )
    
    for i in range(1,4):
        t = threading.Thread(target=producer,args=(i,))
        t.start()
    
    
    def consumer(id):
        """
        消费者
        :return:
        """
        while True:
            time.sleep(1)
            v1 = q.get()
            print('顾客 %s 吃了一个包子' % id)
    
    for i in range(1,3):
        t = threading.Thread(target=consumer,args=(i,))
        t.start()

    锁  线程  线程池  threading.local  生成着消费者模型   

    概念性理解    配合代码

    面试100%提问  GIL锁   线程  进程的区别   IO密集

      

              

  • 相关阅读:
    虚拟机(VM) windows server2003 里终于有声音了 Kenny
    web 打印 webrower 控件的ExecWB 及 兼容IE6 IE7 IE8 打印 办法 Kenny
    周三了,工作状态还没调回来 Kenny
    [转]javascript 异步调用 后台.cs里的方法 PageMethods如何使用 Kenny
    FLASHSPI
    函数指针的使用:使程序跳转到Flash指定位置
    关于内存对齐
    SD卡实验:神舟IV
    LCD 横屏竖屏
    全局变量、局部变量、静态全局变量、静态局部变量的区别
  • 原文地址:https://www.cnblogs.com/SUIFAN/p/9629669.html
Copyright © 2011-2022 走看看