GIL全局解释锁
- GIL与python语言没有关系,仅仅由于历史原因在Cpython虚拟机(解释器)中难以移除
- 每个线程在执行的过程中都要先获取GIL,保证同一时刻只有一个线程可以执行代码
- 线程释放GIL:在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
- Python可以使用多进程来利用多核的CPU资源
- 多线程在网络编程中比单线程性能有提升,因为碰到IO阻塞会自动释放GIL锁(发送请求的等待响应时立马发送下一个请求)
计算密集型使用CUP用进程,IO密集型用线程、协程,线程和协程只有一个CPU在计算
深拷贝、浅拷贝
Python中的深拷贝会复制对象本身并新建一个对象,浅拷贝则只是在原本的对象中加了一个新的引用。
浅拷贝
a = [1,2]
b = a #将b指向列表,并没有新建一个[1,2]列表,C语言会新建一个一样的列表,即在python中a,b的地址一样
深拷贝
import copy
a = [1,2]
b = copy.deepcopy(a) #新建一个[1,2]的列表,ab的地址不同
python 并发
引入并发,是为了提升程序运行速度
python 并发编程的三种方式
CPU密集型和IO密集型
多线程、多进程、多协程
多线程
1、准备一个函数
def my_func(a,b):
do_something(a,b)
2、多线程
import threading
t = threading.Thread(target=my_func,args=(100,200,)) #创建一个线程
t.start() #启动线程
t.join() #等待结束
实例
def multi_thread():
threads = []
for i in range(5):
threads.append(
threading.Tread(target=my_func,args=(100,200,)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
lock解决线程安全问题
线程池
使用进程池的好处
TreadPoolExecutor
from concurrent.futures import TreadPoolExecutor,as_completed
map函数
with ThreadPoolExecutor()as pool:
results = pool.map(my_func,urls) #my_func为执行函数名,urls为参数列表
for result in results:
print(result)
future模式 更强大
with ThreadPoolExecutor()as pool:
futures = [pool.submit(my_func,url)for url in urls]
for future in futures:
print(future.result()) #等待执行结果进行返回
for future in as_completed(futures): #使用as_completed顺序不固定
print(future.result()) #先执行完的先返回
多进程
协程
python异步IO库介绍:asyncio
import asyncio
#获取事件循环
loop = asyncio.get_event_loop()
#定义协程
async def my_func(url):
await get_url(url) #io走到这里不进行阻塞(等待)而是获取下一个事件循环
#创建task列表
tasks = [loop.create_task(my_func(url))for url in urls] #对应第一行代码
#执行事件列表
loop.run_until_complete(asyncio.wait(tasks))
注:requests库不支持异步,要使用aiohttp实现
aiohttp
import aiohttp
import asyncio
async def main():
# 创建aiohttp会话处理请求
async with aiohttp.ClientSession() as session:
tasks = [] # 要执行的任务
for url in urls:
task = asyncio.ensure_future(download(session, url)) # 需要异步执行的函数,不用等结果返回
tasks.append(task)
result = await asyncio.gather(*tasks) # 获取tasks内容,*tasks表示task1 task2 ...., result是一个保存所有任务执行download()后返回的数据的列表,
async def download(session, url):
async with session.get(url) as response:
result_data = await response.json()
return result_data
# 运行异步函数需要使用循环
asyncio.run(main()) # 创造循环