1、GIL全局解释器锁
1、GIL是CPython解释器的特点, 在其它解释器中不存在
2、GIL本质是一把互斥锁,但它是解释器级别的锁
3、它的存在是因为CPython解释器内存管理不是线程安全的
内存管理,即垃圾回收机制,包括
引用计数
标记清除
分代回收
4、GIL的存在导致了用一个进程下的多个线程无法利用多核优势
5、针对不同的数据应该加不同的锁来保证安装
2、互斥锁、死锁与递归锁
中1.4同步
3、信号量
- 信号量在不同的阶段可能对应不同的技术点
- 在并发编程中信号量指的是锁
from threading import Semaphore, Thread
import time
import random
sm = Semaphore(5)
def task(name):
sm.acquire()
print("%s 正在执行" % name)
time.sleep(random.randint(1, 5))
sm.release()
if __name__ == "__main__":
for i in range(20):
t = Thread(target=task, args=('%s 号' % i,))
t.start()
4、Event
# 一些线程/进程等待另外一些线程/进程发送可以运行的信号, 才开始运行
from theading import Event
e = Event()
# 等待
e.wait()
# 发送信号
e.set()
5、队列
- Queue
先进先出 - LifoQueue
后进先出 - PriorityQueue
可以给放入队列中的数据设置优先级
数字越小,优先级越高
6、池
"""
它的出现是为了保证计算机硬件的安全
降低了程序的运行效率,但是保证了计算机硬件安全
"""
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
pool = ThreadPoolExecutor(5) # 池子里面固定只有五个线程
"""
括号内可以传数字,不传的话默认会开设当前计算机CPU个数五倍的线程
池子造出来之后,里面会固定存在五个线程,这5个线程不会重复创建和销毁
"""
"""
将任务提交给池子,就能使用
"""
def task(n):
print(n)
return n * n
"""
任务的提交方式:
同步:提交任务之后原地等待任务的返回结果,期间不做任何事情
异步:提交任务之后不等待任务的返回结果,继续往下执行
"""
def task_call(n):
print(">>>> %s" % n.result())
for i in range(20):
pool.submit(task, i).add_done_callback(task_call) # submit异步提交
# submit其实会返回一个Future类的对象,该对象调用result就能获取到任务的结果
# 池子对象的方法
# pool.shutdown() # 关闭池子,等待池子中所有的任务运行结束,再继续往后执行代码
# 异步回调机制
# 给每一个异步提交的任务绑定一个方法,一旦任务有结果了会立即自动触发该方法
7、总结
多进程下面开设多线程
多线程下面再开设协程
从而使程序执行效率提升