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()

  

posted @ 2019-11-06 23:42  小白686  阅读(120)  评论(0)    收藏  举报