异步IO Python语法-多进程、多线程、协程( 三 )

结果
123456789ThreadPoolExecutor-0_0单个任务返回:103------------------------------ThreadPoolExecutor-0_0ThreadPoolExecutor-0_1ThreadPoolExecutor-0_2多个任务返回:101多个任务返回:103多个任务返回:105  
多进程引用模块 12345678from multiprocessing import Processdef func(num):return numt = Process(target=func, args=(100,))t.start()t.join()  
数据通信 1234import multiprocessingq = multiprocessing.Queue()q.put(1)item = q.get()  
12345from multiprocessing import Locklock = Lock()with lock:pass  
池化技术 12345678from concurrent.futures import ProcessPoolExecutorwith ProcessPoolExecutor() as executor:# 方法1results = executor.map(func, [1, 2, 3])# 方法2future = executor.submit(func, 1)result = future.result()  
示例 12345678910111213141516171819202122232425from concurrent.futures import ProcessPoolExecutorimport multiprocessingimport time# 定义一个准备作为进程任务的函数def action(num):print(multiprocessing.current_process().name)time.sleep(num)return num + 100if __name__ == "__main__":# 创建一个包含3条进程的进程池with ProcessPoolExecutor(max_workers=3) as pool:future1 = pool.submit(action, 3)future1.result()print(f"单个任务返回:{future1.result()}")print('------------------------------')# 使用线程执行map计算results = pool.map(action, [1, 3, 5])for r in results:print(f"多个任务返回:{r}") 结果
123456789SpawnProcess-1单个任务返回:103------------------------------SpawnProcess-2SpawnProcess-3SpawnProcess-1多个任务返回:101多个任务返回:103多个任务返回:105  
多进程/多线程/协程对比异步 IO(asyncio)、多进程(multiprocessing)、多线程(multithreading)
IO 密集型应用CPU等待IO时间远大于CPU 自身运行时间,太浪费;
常见的 IO 密集型业务包括:浏览器交互、磁盘请求、网络爬虫、数据库请求等
Python 世界对于 IO 密集型场景的并发提升有 3 种方法:多进程、多线程、多协程;
理论上讲asyncio是性能最高的,原因如下:

  1. 进程、线程会有CPU上下文切换
  2. 进程、线程需要内核态和用户态的交互,性能开销大;而协程对内核透明的,只在用户态运行
  3. 进程、线程并不可以无限创建,最佳实践一般是 CPU*2;而协程并发能力强,并发上限理论上取决于操作系统IO多路复用(linux下是 epoll)可注册的文件描述符的极限
那asyncio的实际表现是否如理论上那么强,到底强多少呢?我构建了如下测试场景:
请求10此,并sleep 1s模拟业务查询
  • 方法 1;顺序串行执行
  • 方法 2:多进程
  • 方法 3:多线程
  • 方法 4:asyncio
  • 方法 5:asyncio+uvloop
最后的asyncio+uvloop和官方asyncio 最大不同是用 Cython+libuv 重新实现了asyncio 的事件循环(event loop)部分,
官方测试性能是 node.js的 2 倍,持平 golang 。
异步IO Python语法-多进程、多线程、协程

文章插图
 
顺序串行执行 12345678910111213141516171819import timedef query(num):print(num)time.sleep(1)def main():for h in range(10):query(h)# main entranceif __name__ == '__main__':start_time = time.perf_counter()main()end_time = time.perf_counter()print(f"时间差:{end_time-start_time}")  
多进程 123456789101112131415161718192021from concurrent import futuresimport timedef query(num):print(num)time.sleep(1)def main():with futures.ProcessPoolExecutor() as executor:for future in executor.map(query, range(10)):pass# main entranceif __name__ == '__main__':start_time = time.perf_counter()main()end_time = time.perf_counter()print(f"时间差:{end_time-start_time}")  
多线程 123456789101112131415161718192021from concurrent import futuresimport timedef query(num):print(num)time.sleep(1)def main():with futures.ThreadPoolExecutor() as executor:for future in executor.map(query, range(10)):pass# main entranceif __name__ == '__main__':start_time = time.perf_counter()main()end_time = time.perf_counter()print(f"时间差:{end_time-start_time}")


推荐阅读