昨日回顾
进程互斥锁
让并发变成串行,牺牲了效率,保证效率安全.
mutex = Lock()
# 加锁
mutex.acquire()
# 释放锁
mutex.release()
队列
相当于在内存中开启了一个空间,可以存放一堆数据,这堆数据都得遵循‘先进先出’.
管道 (阻塞) + 锁
q = Queue()
# 添加数据
q.put(1)
# 若队列满了,会原地等待
q.put(1)
# 若队列满了,不会等待直接报错
q.put_nowait(2)
# 获取数据,遵循先进先出
若队列中没数据,会原地等待
q.get() # 1
若队列中没数据,会直接报错
q.get_nowait() # 1
q.empty() # 判断队列是否为空
q.full() # 判断队列是否满了
IPC
进程间通信
通过队列让进程间实现通信.
生产者与消费者
生产者:生产数据的
消费者:使用数据的
目的:解决供需不平衡问题.
通过队列来实现,生产者消费者供需不平衡问题.
线程
1.什么是线程?
进程:资源单位
线程:执行单位
注意:只要开启一个进程就会有一个线程(主线程).
主线程会在进程结束时,一并销毁.
2.为什么要使用线程?
节省内存资
开启进程:
-
开启一个新的内存空间
-
会自带一个主线程
开启线程:
-
一个进程内可以开启多个线程
-
开启线程的资源远小于进程
-
# 创建线程的两种方式
一:
from threading import Thread
def task():
pass
t = Thread(target = task) # 异步提交任务,开启线程
t.start()
t.join() # 主线程等待子线程结束之后再结束
二:
class MyThread(Thread):
def run(self):
# 执行任务
pass
t = MyThread()
t.start
t.join()
线程对象的属性
current_thread().name # 获取当前线程对象的名字
# 返回一个列表,列表中包含当前执行的所有线程对象
print(enumerate())
# 获取当前执行线程的个数
print(activeConunt())
is_alive() # 判断线程是否存活
线程互斥锁
from threading import Lock()
mutex = Lock()
mutex.acquire()
tl
mutex.release()
今日内容
GIL全局解释器锁
python解释器:
1.Cpython:C
2.Jpython:java
3.Ppython:python
GIL全局解释器锁:
基于Cpython
来研究全局解释器锁.
1.GIL
本质是一个互斥锁
2.GIL
目的为了阻止同一个进程内多个线程同时执行(并行)
- 单个进程下的多个线程无法实现并行,但能实现并发
3.这把锁主要是因为CPython的内存管理不是'线程安全'的.
- 内存管理
- 垃圾回收机制
GIL的存在就是为了保证线程安全的.
注意:多个线程过来执行,一旦遇到IO操作,就会立马释放GIL解释器锁,交给下一个先进来的线程.
多线程的作用:
站在两个角度去看问题:
- 四个任务, 计算密集型, 每个任务需要10s:
单核:
- 开启进程
消耗资源过大
- 4个进程: 40s
- 开启线程
消耗资源远小于进程
- 4个线程: 40s
多核:
- 开启进程
并行执行,效率比较高
- 4个进