Python 中的多线程和多处理

发布:2024-10-15 13:39 阅读:17 点赞:0

一. 引言

在这篇博客中,我们将探讨多线程和多进程在 Python 中的应用。在当今多核处理器的世界里,利用并发编程技术至关重要,以优化性能。Python 提供了两个强大的模块用于并行执行:threading 用于多线程,而 multiprocessing 用于多进程。

二. Python 中的多线程

多线程允许多个线程在单个进程中并发运行。对于 I/O 密集型任务(如网络请求、文件操作等)来说,多线程尤其有效,因为这些任务往往需要等待外部操作完成。下面我们将通过一个示例,展示如何使用多线程进行网页抓取。

示例

我们将创建一个简单的网页抓取程序,并同时从多个 URL 下载内容。在运行以下示例之前,请确保使用 pip install requests 安装 requests 包。

import threading  # 导入 threading 模块
import requests  # 导入 requests 模块
import time  # 导入 time 模块

# 定义下载内容的函数
def download_content(url):
    response = requests.get(url)  # 发送 GET 请求获取网页内容
    print(f"Downloaded {len(response.content)} bytes from {url}")  # 输出下载的字节数

# 定义要抓取的 URL 列表
urls = [
    "https://www.python.org",  # Python 官方网站
    "https://www.github.com",  # GitHub 官方网站
]

start_time = time.time()  # 记录开始时间

threads = []  # 存储线程的列表
for url in urls:  # 遍历每个 URL
    thread = threading.Thread(target=download_content, args=(url,))  # 创建线程
    threads.append(thread)  # 将线程添加到列表中
    thread.start()  # 启动线程

for thread in threads:  # 等待所有线程完成
    thread.join()  # 等待线程结束

end_time = time.time()  # 记录结束时间
print(f"Total execution time: {end_time - start_time:.2f} seconds")  # 输出总执行时间

在上面的 Python 代码中,为每个 URL 创建了一个独立的线程,允许同时下载内容。join() 方法确保所有线程在程序退出之前完成。

三. Python 中的多进程

虽然多线程受限于 CPython 的全局解释器锁(GIL),多进程可以通过生成独立的 Python 进程来充分利用多个 CPU 核心。接下来,我们将通过一个示例来计算质数。

示例

我们将使用多个进程来计算质数。

import multiprocessing  # 导入 multiprocessing 模块
import time  # 导入 time 模块

# 定义检查质数的函数
def is_prime(n):
    if n < 2:  # 如果小于 2,返回 False
        return False
    for i in range(2, int(n ** 0.5) + 1):  # 检查从 2 到 n 的平方根之间的数
        if n % i == 0:  # 如果能整除,返回 False
            return False
    return True  # 返回 True,表示是质数

# 定义查找质数的函数
def find_primes(start, end):
    return [num for num in range(start, end) if is_prime(num)]  # 返回指定范围内的所有质数

if __name__ == "__main__":  # 确保主程序运行
    start_time = time.time()  # 记录开始时间

    pool = multiprocessing.Pool(processes=4)  # 创建进程池,指定进程数量
    ranges = [(125000), (2500150000), (5000175000), (75001100000)]  # 定义范围
    results = pool.starmap(find_primes, ranges)  # 使用 starmap 并行执行查找质数的函数

    all_primes = [prime for sublist in results for prime in sublist]  # 将所有子列表合并为一个列表

    end_time = time.time()  # 记录结束时间
    print(f"Found {len(all_primes)} prime numbers")  # 输出找到的质数数量
    print(f"Total execution time: {end_time - start_time:.2f} seconds")  # 输出总执行时间

在上面的 Python 代码中,使用一个进程池来将质数计算任务分配到多个 CPU 核心上。

四. 选择多线程还是多进程

  • 对于 I/O 密集型任务(如网络操作、文件 I/O),使用多线程。
  • 对于需要并行计算的 CPU 密集型任务,使用多进程。
  • 多线程占用系统资源较少,但受限于 GIL。
  • 多进程开销更大,但可以充分利用多个 CPU 核心。

五. 总结

多线程和多进程都是提升 Python 应用性能的强大工具。通过理解它们的优势和适用场景,您可以为具体需求选择合适的方法,以提升程序的执行效率。