程序员文章、书籍推荐和程序员创业信息与资源分享平台

网站首页 > 技术文章 正文

第十四章:Python并发编程(python并发原理)

hfteth 2025-07-08 18:15:30 技术文章 3 ℃

14.1 多线程编程

14.1.1 理论知识

多线程编程允许在一个程序中同时运行多个线程,每个线程都可以独立执行任务。在 Python 中,threading 模块提供了对多线程的支持。线程共享进程的资源,这使得线程间通信相对容易,但也带来了资源竞争的问题,需要通过锁机制等手段来避免。

14.1.2 示例代码

import threading


def print_numbers():
    for i in range(1, 6):
        print(f"线程 {threading.current_thread().name} 打印: {i}")


def print_letters():
    for letter in 'abcde':
        print(f"线程 {threading.current_thread().name} 打印: {letter}")


if __name__ == '__main__':
    thread1 = threading.Thread(target = print_numbers)
    thread2 = threading.Thread(target = print_letters)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

14.1.3 代码解释

  • 定义了两个函数 print_numbers 和 print_letters,分别用于打印数字和字母。
  • 使用 threading.Thread 创建两个线程 thread1 和 thread2,分别指定它们要执行的目标函数。
  • 通过 start() 方法启动这两个线程,此时两个线程开始并发执行。
  • 使用 join() 方法等待线程完成,确保主线程在两个子线程都执行完毕后再结束。

14.2 多进程编程

14.2.1 理论知识

多进程编程是指在一个程序中同时运行多个进程。与多线程不同,每个进程都有自己独立的内存空间,这使得进程间通信相对复杂,但也避免了线程间资源竞争的问题。在 Python 中,multiprocessing 模块用于多进程编程。

14.2.2 示例代码

import multiprocessing


def square_number(num):
    result = num * num
    print(f"进程 {multiprocessing.current_process().name} 计算: {num} 的平方是 {result}")


if __name__ == '__main__':
    numbers = [1, 2, 3, 4, 5]
    processes = []

    for num in numbers:
        process = multiprocessing.Process(target = square_number, args=(num,))
        processes.append(process)
        process.start()

    for process in processes:
        process.join()

14.2.3 代码解释

  • 定义了 square_number 函数,用于计算并打印一个数的平方。
  • 创建一个数字列表 numbers,并初始化一个空列表 processes 用于存储进程对象。
  • 通过循环为每个数字创建一个进程,将 square_number 函数作为目标函数,并传递数字作为参数。
  • 启动每个进程,然后通过 join() 方法等待所有进程完成,确保所有进程执行完毕后程序结束。

14.3 线程池与进程池

14.3.1 理论知识

线程池和进程池是一种管理线程和进程的方式,它们预先创建一定数量的线程或进程,当有任务时,从池中获取可用的线程或进程来执行任务,任务完成后,线程或进程返回池中等待下一个任务。这样可以避免频繁创建和销毁线程或进程带来的开销,提高性能。在 Python 中,concurrent.futures 模块提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 来实现线程池和进程池。

14.3.2 示例代码(线程池)

import concurrent.futures


def cube_number(num):
    return num * num * num


if __name__ == '__main__':
    numbers = [1, 2, 3, 4, 5]
    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = list(executor.map(cube_number, numbers))
    print(results)

14.3.3 代码解释

  • 定义 cube_number 函数用于计算一个数的立方。
  • 创建数字列表 numbers,使用 concurrent.futures.ThreadPoolExecutor 创建线程池。
  • 使用 executor.map() 方法将 cube_number 函数应用到 numbers 列表的每个元素上,返回一个可迭代对象,通过 list() 将其转换为列表并赋值给 results。最后打印计算结果。

14.3.4 示例代码(进程池)

import concurrent.futures


def factorial(num):
    if num == 0 or num == 1:
        return 1
    else:
        return num * factorial(num - 1)


if __name__ == '__main__':
    numbers = [3, 4, 5]
    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = list(executor.map(factorial, numbers))
    print(results)

14.3.5 代码解释

  • 定义 factorial 函数用于计算一个数的阶乘。
  • 创建数字列表 numbers,使用 concurrent.futures.ProcessPoolExecutor 创建进程池。
  • 同样使用 executor.map() 方法将 factorial 函数应用到 numbers 列表的每个元素上,获取计算结果并转换为列表打印。

14.4 异步编程

14.4.1 理论知识

异步编程允许程序在执行某些 I/O 操作(如网络请求、文件读取等)时,不阻塞主线程,而是继续执行其他任务,从而提高程序的整体效率。在 Python 中,asyncio 是用于异步编程的标准库,通过 async 和 await 关键字来定义和管理异步函数。

14.4.2 示例代码

import asyncio


async def async_task(task_name):
    print(f"{task_name} 开始")
    await asyncio.sleep(2)
    print(f"{task_name} 结束")


async def main():
    tasks = [async_task(f"任务{i}") for i in range(3)]
    await asyncio.gather(*tasks)


if __name__ == '__main__':
    asyncio.run(main())

14.4.3 代码解释

  • 定义异步函数 async_task,它打印任务开始信息,使用 await asyncio.sleep(2) 模拟一个耗时 2 秒的异步操作,然后打印任务结束信息。
  • 定义 main 异步函数,创建三个 async_task 任务的列表 tasks,使用 asyncio.gather(*tasks) 并发运行这些任务。
  • 使用 asyncio.run(main()) 来运行 main 异步函数,启动整个异步任务流程。
最近发表
标签列表