Python的GIL锁 - Python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度。 为什么有这把GIL锁? 答:Python语言的创始人在开发这门语言时,目的快速把语言开发出来,如果加上GIL锁(C语言加锁),
切换时按照100条字节指令来进行线程间的切换。
一、锁: Lock
1、一次放一个
threading.Lock
线程安全,多线程操作时,内部会让所有线程排队处理。如:list/dict/ Queue 线性不安全 + 人 =》 排队处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()
2、一次放指定N个
BoundedSemaphore
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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()
总结
线程安全,列表和字典线程安全; 为什么要加锁? - 非线程安全 - 控制一段代码
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()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 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()
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()