在 Python 编程中,当我们想让程序 “同时做几件事” 时,总会绕不开线程和进程这两个概念。比如爬取多个网页、处理大批量数据、实时监控系统状态,都需要用到多线程或多进程来提升效率。本文用最通俗的语言讲清线程、进程的核心区别,以及 Python 中如何简单使用它们,零基础也能看懂。
一、先搞懂:线程和进程到底是什么?
用一个生活化的例子就能秒懂:
- 进程:相当于你电脑上打开的一个 “应用程序”(比如微信、浏览器、PyCharm)。每个应用程序都是一个独立的进程,系统会给每个进程分配专属的资源(比如内存空间、CPU 时间片)。
- 线程:相当于应用程序里的 “一个功能模块”(比如微信的 “接收消息”“刷朋友圈”“发文件”)。一个进程可以包含多个线程,这些线程共享进程的资源,协同完成应用的功能。
核心定义(简单版)
| |
|---|
| 进程里的 “最小执行单位”,一个进程可以有多个线程,比如浏览器里同时加载图片和文字 |
| 独立的 “应用程序实例”,系统分配资源的基本单位,比如单独的微信进程、QQ 进程 |
| 一个程序里同时跑多个线程(比如爬虫程序同时爬 10 个网页) |
| 系统里同时跑多个相同 / 不同的程序进程(比如同时启动 3 个 Python 脚本处理数据) |
二、线程 vs 进程:核心区别(5 个关键点)
这是最容易混淆的部分,用表格总结核心差异,一眼看清:
| | |
|---|
| | |
| | 仅共享物理内存、磁盘等系统级资源,进程间不共享数据 |
| | |
| | |
| | |
举个例子:
- 多线程:你用一个浏览器(进程)同时打开 5 个标签页(线程),所有标签页共享浏览器的内存和网络连接,切换标签页几乎无延迟;
- 多进程:你打开 3 个不同的浏览器(Chrome、Edge、Firefox),每个浏览器都是独立进程,各自占用内存,进程间无法直接共享数据。
三、Python 多线程实战:用 threading 快速上手
Python 推荐用 threading 模块(高级封装,支持守护线程),而非低级的 _thread 模块。下面用 “同时打印数字和字母” 的例子,演示多线程的基本用法:
1. 基础示例:多线程执行不同任务
python
运行
import threadingimport time# 定义线程1要执行的函数:打印数字def print_numbers(): for i in range(5): print(f"数字:{i}") time.sleep(1) # 暂停1秒,模拟耗时操作# 定义线程2要执行的函数:打印字母def print_letters(): for letter in ["A", "B", "C", "D", "E"]: print(f"字母:{letter}") time.sleep(1)if __name__ == "__main__": # 创建线程对象 t1 = threading.Thread(target=print_numbers) t2 = threading.Thread(target=print_letters) # 启动线程 t1.start() t2.start() # 等待所有线程执行完毕(主线程阻塞) t1.join() t2.join() print("所有线程执行完成!")
2. 运行结果(核心:数字和字母交替打印)
plaintext
数字:0字母:A数字:1字母:B数字:2字母:C数字:3字母:D数字:4字母:E所有线程执行完成!
关键说明:
threading.Thread(target=函数名)start()join():让主线程等待子线程执行完毕,避免主线程提前退出导致子线程被强行终止;- 守护线程:如果想让子线程随主线程退出而结束,可设置
t1.daemon = True(比如后台监控线程)。
四、Python 多进程实战:用 multiprocessing 实现并行
Python 的 multiprocessing 模块专门处理多进程,适合 CPU 密集型任务(比如数据计算)。下面用 “多进程计算平方数” 演示用法:
1. 基础示例:多进程处理数据
python
运行
from multiprocessing import Processimport time# 定义进程要执行的函数:计算并打印平方数def calculate_square(num): time.sleep(1) # 模拟耗时计算 result = num * num print(f"数字 {num} 的平方是:{result}")if __name__ == "__main__": # 要计算的数字列表 numbers = [1, 2, 3, 4, 5] processes = [] # 创建并启动多个进程 for num in numbers: p = Process(target=calculate_square, args=(num,)) # args 传递参数(元组形式) p.start() processes.append(p) # 等待所有进程完成 for p in processes: p.join() print("所有进程计算完成!")
2. 运行结果(核心:多个进程并行计算)
plaintext
数字 1 的平方是:1数字 2 的平方是:4数字 3 的平方是:9数字 4 的平方是:16数字 5 的平方是:25所有进程计算完成!
关键说明:
Process(target=函数名, args=(参数,))- 多进程必须放在
if __name__ == "__main__": 下(Windows 系统要求,避免进程递归创建); - 进程间通信:如果需要进程间共享数据,可使用
Queue(队列)或 Pipe(管道),比如 from multiprocessing import Queue。
五、什么时候用多线程?什么时候用多进程?
这是最关键的选型问题,记住两个核心原则:
1. 用多线程的场景
- IO 密集型任务:比如网络请求(爬虫)、文件读写、数据库操作(等待服务器响应的时间占比高);
- 原因:IO 等待时线程会释放 CPU,切换到其他线程执行,能充分利用时间,且线程开销小。
2. 用多进程的场景
- CPU 密集型任务:比如数据计算、图像渲染、复杂算法(CPU 一直处于忙碌状态);
- 原因:Python 有 GIL(全局解释器锁),多线程无法利用多核 CPU,而多进程可绕过 GIL,充分利用多核优势。
举个例子:
- 对爬取的 100 万条数据做统计计算 → 多进程。
六、总结
- 核心概念:线程是进程内的最小执行单位,进程是独立的应用程序实例;
- 核心区别:线程共享进程资源(开销小、通信简单),进程独立(开销大、通信复杂);
- 使用场景
- Python 工具:多线程用
threading,多进程用 multiprocessing。