Skip to main content

Python 的多线程在处理 I/O 密集型任务时非常有用。下面我会系统地讲解 Python 多线程地核心知识点,并重点深入解释你提到地几个关键问题(守护线程、join()等)

一、Python 多线程基础

Python 中的多线程主要通过 threading 模块实现。每个线程都是 threading.Thread 类的一个实例。

1.1 创建线程的两种方式

# 方法一:传入函数
import threading

def task():
print("子线程执行任务")

t = threading.Thread(target=task)
t.start()

# 方法二:继承Thread类
class MyThread(threading.Thread):
def run(self):
print("子线程执行任务")

t = MyThread()
t.start()

二、Thread类中的核心参数详解

threading.Thread(
group=None,
target=None,
name=None,
args=(),
kwargs={},
daemon=None
)

✅ 关键参数解释:

参数名说明
target要执行的函数对象
args给目标函数传的位置参数(元组)
kwargs给目标函数传的关键字参数(字典)
name线程名称,默认自动生成
daemon是否是“守护线程”(重点解释如下)

三、什么是守护线程(daemon)

3.1 基本理解:

守护线程是 依附于主线程 的线程。如果主线程(程序入口)结束了,那么 所有还在运行的守护线程都会被强制终止

🌟 类比理解:

可以把主线程看作 ”主进程“,守护线程就是 ”打杂的小弟“。主线程死了,小弟自动也跟着被干掉,连收拾残局的机会都没有。

🧪 示例:

import threading
import time

def worker():
while True:
print("子线程运行中...")
time.sleep(1)

t = threading.Thread(target=worker)
t.daemon = True # 设置为守护线程
t.start()

time.sleep(3)
print("主线程结束")

输出结果:

子线程运行中...
子线程运行中...
子线程运行中...
主线程结束
(程序退出,守护线程被强制关闭)

❗ 注意:

  • 一定要在 start() 之前设置 daemon = True,否则会报错。
  • 守护线程不会执行任何 ”清理“ 或 ”善后“ 代码(如 finally 块)。

⛓️ 四、线程的 join()

4.1 基本定义:

join() 的作用是:让主线程等待子线程执行完成后再继续执行

👀 谁对谁可见?

主线程调用子线程的 join(),意思是让主线程 ”卡住等你执行完“。

🌟 示例说明:

import threading
import time

def worker():
print("子线程开始")
time.sleep(2)
print("子线程结束")

t = threading.Thread(target=worker)
t.start()

print("主线程等待子线程")
t.join() # 等待子线程执行完成
print("子线程执行完了,主线程继续")

输出:

子线程开始
主线程等待子线程
子线程结束
子线程执行完了,主线程继续

💥 五、join() 后子线程还存在吗?会立即销毁吗?

这个问题非常好,也是很多人搞混的点。

✅ 正确理解:

  • 调用 join() 并不是销毁线程,而是 ”等这个线程运行完“。
  • 线程结束后,线程对象依然存在,只是状态变成了 ”终止“ (t.is_alive() == False)。
  • Python 会自动做资源清理,不需要我们手动销毁线程对象。

🔍 验证示例:

import threading
import time

def worker():
print("子线程执行")
time.sleep(1)

t = threading.Thread(target=worker)
t.start()
t.join()

print("子线程还活着吗?", t.is_alive())

输出:

子线程执行
子线程还活着吗? False

所以你看到的是,线程运行完后,确实不再“活着”了,但它的对象还在,只是状态改变了

🔁 六、守护线程 vs 非守护线程 vs join() 的配合理解

场景效果
非守护线程 + 不 join主线程执行完后,会等子线程执行完才退出
守护线程 + 不 join主线程结束后,子线程立即被强制终止
非守护线程 + join主线程会等待子线程执行完,确保同步
守护线程 + join正常等待,join 优先级高,主线程会等子线程执行完(只要主线程不先结束)

🧩 七、结语和建议

如果你刚开始学多线程,可以先牢牢记住以下几点:

  1. daemon=True 是“我不重要,主线程结束我就结束”。
  2. join() 是“你别走,等我干完这件事再走”。
  3. 一般 I/O 操作(如爬虫、网络请求)适合用多线程来加速。
  4. 如果有资源共享需求,一定注意线程同步(如使用 Lock)。