zoukankan      html  css  js  c++  java
  • day 33 线程锁

    Python的GIL锁
        - Python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度。
    为什么有这把GIL锁?
        答:Python语言的创始人在开发这门语言时,目的快速把语言开发出来,如果加上GIL锁(C语言加锁),
        切换时按照100条字节指令来进行线程间的切换。

     

    一、锁: Lock

    1、一次放一个

      threading.Lock

    线程安全,多线程操作时,内部会让所有线程排队处理。如:list/dict/ Queue
    线性不安全 + 人 =》 排队处理
    
    import threading
    
    v = []
    def func(arg):
        v.append(arg) # 线程安全
        print(v)
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    线性安全
    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()
    锁Lock
    import threading
    import time
    
    v = []
    lock = threading.RLock()
    def func(arg):
        lock.acquire()
        lock.acquire()   #RLock可以进行多次加锁
    
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
    
        lock.release()  #RLock多次释放锁
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    锁 Rlock

    2、一次放指定N个

      BoundedSemaphore

    import time
    import threading
    
    lock = threading.BoundedSemaphore(3)  #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()
    BoundedSemaphore

    3、一次释放N 个

      Condition

    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.wait() 就是代表释放几个线程
        lock.release()
    # ############## 方式二 ##############
    
    def xxxx():
        print('来执行函数了')
        input(">>>")
        # ct = threading.current_thread() # 获取当前线程
        # ct.getName()
        return True
    
    def func(arg):
        print('线程进来了')
        lock.wait_for(xxxx)  #等待xxxx中的东西执行完成之后,此线程才会接着往下走
        print(arg)
        time.sleep(1)
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()

    4、一次放所有

      Event

    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()
    Event
    总结
    线程安全,列表和字典线程安全; 为什么要加锁? - 非线程安全 - 控制一段代码

      

     5、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()
    # by luffycity.com
    import time
    import threading
    
    DATA_DICT = {}
    
    def func(arg):
        ident = threading.get_ident()
        DATA_DICT[ident] = arg     #就是每一个ID都会存放一个数据,查找的时候通过id查找数据
        time.sleep(1)
        print(DATA_DICT[ident],arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    #原理(深入了解)(可选)
    import time
    import threading
    INFO = {}
    class Local(object):
    
        def __getattr__(self, item):
            ident = threading.get_ident()
            return INFO[ident][item]
    
        def __setattr__(self, key, value):
            ident = threading.get_ident()
            if ident in INFO:
                INFO[ident][key] = value
            else:
                INFO[ident] = {key:value}
    
    obj = Local()
    
    def func(arg):
        obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
        time.sleep(2)
        print(obj.phone,arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    threadinglocal原理

     6、线程池

       创建多个线程池,用户需要几个线程去线程池里面去拿。(常用)

    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)

    7、生产者消费者模型

        三部件:
            生产者 
                队列,先进先出
                    扩展: 栈,后进先出
            消费者 
        
        问:生产者消费者模型解决了什么问题?
          不用一直等待的问题。
    # by luffycity.com
    import time
    import queue
    import threading
    q = queue.Queue() # 线程安全
    
    def producer(id):
        """
        生产者
        """
        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):
        """
        消费者
        """
        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()

      

  • 相关阅读:
    ubuntu上搭建review board代码评审站点
    android5.1 for tq335x
    2015.04.11
    DECLARE_GLOBAL_DATA_PTR宏定义问题
    6410移植android4.4.2笔记(持续更新)
    ubuntu安装packet提示重复冲突问题
    android5.0 aosp编译记录(由于机器硬件原因,改为4.4.2编译通过)
    2015.01.16
    2015.01.14
    SDSM框架
  • 原文地址:https://www.cnblogs.com/xiaobai686/p/11809519.html
Copyright © 2011-2022 走看看