python并发编程的三种方式:多进程、多线程、多协程介绍

1. 定义

多进程Process:multiprocessing,利用多核CPU的能力,真正的并行执行任务

多线程Thread:threading,利用CPU和IO可以同时执行的原理,让CPU不再等待IO的完成

多协程Coroutine(异步IO):asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行

多进程、多线程、多协程 的对比
优点缺点适用于
多进程Process可以利用多核CPU并行计算占用资源最多、可启动数目比线程少CPU密集型计算
多线程Thread

相比进程,更轻量级、占用资源少  

相比进程:多线程只能并发执行,不能利用多CPU(GIL)

相比协程:启动数目有限制,占用内存资源,有线程切换开销

IO密集型计算、同时运行的任务数目要求不多
多协程Coroutine(异步IO)内存开销最少、启动协程数量最多       支持的库有限制、代码实现复杂IO密集型计算、需要超多任务运行、但有现成库支持的场景

2. 相关知识点

2.1 CPU密集型(CPU-Bound)

        CPU密集型也叫计算密集型,是指IO在很短时间就可以完成,CPU需要大量的计算和处理,特点是CPU占用率相当高。例如:压缩解压缩、加密解密、正则表达式搜索、机器训练

2.2 IO密集型(IO Bound)

        IO密集型指的是系统运作大部分的状态是CPU在等IO(硬盘内存)的读写操作,CPU占用率仍然较低。例如:文件处理程序、网络爬虫程序、读写数据库程序、网页后端接口程序

2.3 全局解释器锁GIL(Global Interpreter Lock)

        是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即便在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。

        多线程用于IO密集型计算在IO读写期间,线程会释放GIL,实现CPU和IO的并行,因此多线程在IO密集型可大幅提示速度,但在CPU密集型计算,因为线程切换的开销,只会拖慢速度。

        使用multiprocessing的多进程机制实现并行计算,利用多核CPU优势实现多个解释器的运行,不受GIL的限制。

2.4 多组件的Pipeline技术架构

复杂的事情一般不会一下子做完,而是分为很多中间步骤一步一步完成,如下图所示。

        实际应用中,后级任务比前级任务需要更多的资源和时间进行执行,如果直接执行的话,前级任务很快被执行完毕,大多数时间都在等待后级任务的执行。并发编程的思想就是通过分解执行的任务,根据任务的复杂程度和所需要的时间和资源,分配任务的并发数量。

2.5 生产者消费者架构

        多组件的Pipeline架构中第一级和第二级组成的架构就叫生产者消费者架构,这也是并发编程应用最多的场景。如下图所示,爬虫程序一般要先从网页中爬取URL,通过URL进行网页信息的解析和存储。前级任务相对简单,可以作为生产者不断生产URL,后级任务需要更多的资源和时间进行内容的解析和入库,需要分配更多的并发数量。

2.6 线程安全

线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。

2.7 线程的生命周期

3 数据通信

多线程通信:queue.Queue 可用于多线程之间的、线程安全的数据通信

# 1 导入类库
import queue
# 2 创建Queue
thread_queue = queue.Queue()
# 3 添加元素
thread_queue.put("test")
# 4 获取元素
item = thread_queue.get()  # 阻塞式的,如果没有数据会一直卡在这里等待获取到数据为止
# 5 查询状态
thread_queue.qsize()  # 5.1 查看元素的数量
thread_queue.empty()  # 5.2 查看是否为空
thread_queue.full()  # 5.3 查看是否已满

4 安全锁

# 1 导入类库
import threading

# 2 实例化一把安全锁
lock = threading.Lock()
# 3 用法1: try-finally 模式
lock.acquire()
try:
    # do something
    pass
finally:
    lock.release()
# 4 用法2: with 模式
with lock:
    # do somethin
    pass

5 池化技术

        新建线程系统需要分配资源、终止线程系统需要回收资源,如果可以重用线程,就可以减去新建和终止线程的开销。

提升性能:因为减去大量新建、终止线程的开销,重用了线程资源

使用场景:适合处理突发大量请求或需要大量线程完成任务、但实际任务处理时间较短

防御功能:能够有效避免系统因为创建线程过多,而导致系统负荷过大相应变慢等问题

代码优势:使用线程池的语法比自己新建线程执行线程更加简洁

# 引入依赖
from concurrent.futures import ThreadPoolExecutor, as_completed

# 用法1 map函数,简单,注意map的结果和入参顺序对应
with ThreadPoolExecutor()as pool:
    results = pool.map(method, argus)  # method 函数名, argus 参数列表

    for result in results:
        print(result)
# 用法2 future模式,更强大,结果和入参顺序对应
with ThreadPoolExecutor() as pool:
    futures = [pool.submit(method, argus) for argu in argus]

    for future in futures:
        print(future.result())
    # as_completed是按任务完成先后顺序返回
    for future in as_completed(futures):
        print(future.result())

6 多进程 多线程对比

7 多协程的创建

7.1 旧版本创建协程的方法

import asyncio


async def task1():
    while True:
        print("Task 1 is running")
        await asyncio.sleep(1)


async def task2():
    while True:
        print("Task 2 is running")
        await asyncio.sleep(1)


def main_task():
    # 创建一个事件循环
    loop = asyncio.get_event_loop()
    loop.create_task(task1())  # 在此事件循环中添加异步任务1
    loop.create_task(task2())  # 在此事件循环中添加异步任务2
    loop.run_forever()  # 启动事件循环

7.2 新版本创建协程的方法

import asyncio


async def task1():
    while True:
        print("Task 1 is running")
        await asyncio.sleep(1)


async def task2():
    while True:
        print("Task 2 is running")
        await asyncio.sleep(1)


async def main_task():
    task1_coro = asyncio.create_task(task1())
    task2_coro = asyncio.create_task(task2())
    # main() 函数使用 asyncio.gather() 并发运行 task1(), task2() 这两个任务。
    await asyncio.gather(task1_coro, task2_coro)


# 使用 asyncio.run() 启动 main() 函数,这是在 Python 3.7 之后推荐的启动异步函数的方式
asyncio.run(main_task())

  • 30
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值