大佬的理解
我的理解
多线程是通过cpu分片实现并行,所有线程雨露均沾(可能操作系统有优化,但本质还是这个),比如一个线程执行到request请求时等待响应,假如响应需要60秒,很快就因为分片到时而释放cpu,但很快该线程又会被分配新的分片又会一直执行到分片到时,循环往复,也就是说这60秒内分配给该线程的cpu分片都是无效的! 协程是通过程序控制调度,当执行io时,可以通过await关键字来避免给任务分配cpu分片,提高cpu的效率。
测试验证
现在有一个需求:需要http请求一个接口100次,假如接口耗时1秒。
多线程和协程分别来实现,有什么区别呢?
可以看到同样是并发,协程的效率远比多线程要好的多!
源码:
多线程:
import concurrent
import time
from concurrent.futures import ThreadPoolExecutor
def request():
# 模拟request请求
time.sleep(1)
return 1
def concurrent_execution():
with ThreadPoolExecutor(max_workers=10) as executor:
futures = {executor.submit(request) for _ in range(100)}
results = []
for future in concurrent.futures.as_completed(futures):
result = future.result()
results.append(result)
return sum(results)
start_time = time.time()
ret = concurrent_execution()
print(f'ret:{ret}, time: {time.time() - start_time}')
协程:
import asyncio
import time
async def aiohttp():
# 模拟aiohttp请求
await asyncio.sleep(1)
return 1
async def concurrent_execution():
tasks = [asyncio.create_task(aiohttp()) for _ in range(100)]
rets = await asyncio.gather(*tasks)
return sum(rets)
start_time = time.time()
ret = asyncio.run(concurrent_execution())
print(f'ret:{ret}, time: {time.time() - start_time}')
注意点
协程避免了【雨露均沾】带来的性能问题,但是需要注意也失去了【雨露均沾】的好处!!!
比如当其他协程一直在运行,而不await(例如下面示例中time.sleep(5)),这时其他协程是没有机会执行的!
可以看到这个示例中,使用多线程时,子线程不会一直等待主线程的sleep,而协程方案会一直等到知道主任务完成。
总计
在使用协程时,尽量不要阻塞,比如调用接口、访问数据库等使用非阻塞的工具包,否则性能不仅得不到提升,反而大大降低了吞吐量(多线程至少还能有机会处理)!假如必须阻塞,那还不如使用多线程!