python的GIL 锁python
python内置的一个全局解释器锁 , 锁的做用就是保证同一时刻一个进程中只有一个线程能够被cpu调度面试
为何有这把GIL锁?安全
python语言的创始人在开发这门语言时 , 目的快速把语言开发出来 , 若是加上GIL锁(C语言加锁) , 切换时按照100条字节指令来进行线程间的切换多线程
锁 : app
1.锁 : Lock(1次放1个)ide
线程安全 , 多线程操做时 , 内部会让全部线程排队处理 , 如 : list / dict / Queue函数
线程不安全 + 人 =>排队处理ui
需求:spa
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密集