Python 多线程使用
一 线程的介绍
1.1 实现多任务的另一种形式
在 Python 中,除了多进程,还可以使用多线程来实现多任务。
1.2 为什么使用多线程
- 资源开销小:进程是分配资源的最小单位,创建一个进程需要分配独立的内存空间,资源消耗较大。
- 共享资源:线程是程序执行的最小单位,同属一个进程的多个线程共享进程的全部资源(如内存、全局变量等)。
- 进程与线程的关系:进程是线程的容器,一个进程中最少有一个线程(主线程)来负责执行程序。
1.3 多线程的概念
在进程中默认有一个线程用来执行程序,这个线程称之为主线程。由主线程创建的新线程称之为子线程。
小结
- 多线程是 Python 程序中实现多任务的一种高效方式。
- 进程是资源分配的基本单位,线程是 CPU 调度的基本单位。
- 线程间共享进程资源,但创建/销毁的开销远小于进程。
二 多线程的基本使用
2.1 线程的创建步骤
启动线程执行任务
线程对象.start()通过线程类创建线程对象
线程对象 = threading.Thread(target=任务名)导入线程模块
import threading 2.2 Thread 类常用参数
| 参数 | 说明 |
|---|---|
| target | 执行的目标任务名(函数名) |
| name | 线程名,如果不指定会自动生成(如 Thread-1) |
| group | 线程组,目前只能使用 None |
2.3 线程创建与启动示例
import threading import time defsing():for i inrange(3):print("唱歌中。。。") time.sleep(0.5)defdance():for i inrange(3):print("跳舞中。。。") time.sleep(0.5)if __name__ =='__main__':# 创建子线程 sing_thread = threading.Thread(target=sing) dance_thread = threading.Thread(target=dance)# 启动线程 sing_thread.start() dance_thread.start()三 线程执行带有参数的任务
与进程类似,线程也可以通过 args 和 kwargs 传递参数。
| 参数名 | 说明 |
|---|---|
| args | 以元组的方式传参 |
| kwargs | 以字典的方式传参 |
import threading import time defsing(num, name):for i inrange(num):print(f"{name}正在唱歌。。。") time.sleep(0.5)defdance(num, name):for i inrange(num):print(f"{name}正在跳舞。。。") time.sleep(0.5)if __name__ =="__main__":# args: 元组传参,顺序需一致;单参数需加逗号 (num,) singer = threading.Thread(target=sing, args=(3,"张三"))# kwargs: 字典传参,key 需与形参名一致 dancer = threading.Thread(target=dance, kwargs={"num":2,"name":"李四"}) singer.start() dancer.start()# 等待子线程结束 singer.join() dancer.join()四 线程的结束顺序
4.1 主线程等待子线程
默认情况下,主线程会等待所有子线程执行结束后再退出。
4.2 设置守护线程
如果希望主线程结束时,子线程也立即结束,可以设置守护线程。
import threading import time defwork():for i inrange(10):print("工作中...") time.sleep(0.2)if __name__ =="__main__":# 方式1:创建时设置 daemon=True# 方式2:线程对象.daemon = True work_thread = threading.Thread(target=work, daemon=True) work_thread.start() time.sleep(1)print("主线程结束,子线程也将随之销毁")五 线程间的执行顺序
5.1 线程执行是无序的
线程的调度由操作系统决定,因此多个线程的执行顺序是不确定的。
5.2 获取线程信息
import threading import time deftask(): time.sleep(1)# 获取当前执行该代码的线程对象 current = threading.current_thread()print(current)if __name__ =='__main__':for i inrange(5): sub_thread = threading.Thread(target=task) sub_thread.start()六 进程与线程的对比
6.1 关系对比
- 线程依附于进程,没有进程就没有线程。
- 一个进程可以包含多个线程,但至少有一个主线程。
6.2 区别对比
- 资源分配:进程是资源分配的基本单位;线程是 CPU 调度的基本单位。
- 开销:创建进程开销大;创建线程开销小。
- 共享:进程间资源独立(需通过 IPC 通信);线程间共享所属进程的资源。
6.3 优缺点对比
- 进程:
- 优点:可以使用多核(并行),稳定性高(一个进程崩溃不影响其他进程)。
- 缺点:资源消耗大。
- 线程:
- 优点:资源消耗小,通信方便。
- 缺点:在 CPython 中受 GIL(全局解释器锁)限制,无法利用多核实现真正的并行(只能并发)。
关于 GIL:
CPython 解释器中存在 GIL,使得同一时刻只有一个线程在 CPU 上运行。因此,多线程在 Python 中更适合 I/O 密集型任务,而多进程更适合 计算密集型任务。
代码地址
https://github.com/lys1313013/python-demos/tree/main/14_%E5%B9%B6%E5%8F%91