Python 多线程从入门到精通:零基础也能学会的并发编程

简介: 本教程来源http://www.phdhk.cn系统讲解Python多线程:从线程/进程概念、GIL限制,到threading模块实操(创建、启动、join、Lock同步),涵盖I/O密集型任务实战对比与避坑指南,助你高效应对并发开发需求。(239字)

前言
在编程中,我们经常遇到需要同时处理多个任务的场景:比如一边下载文件、一边显示进度,一边爬取网页、一边保存数据,一边处理数据、一边响应用户操作。如果用单线程依次执行,效率会极低,而多线程就是解决这类问题的核心技术。
Python 作为一门简洁高效的编程语言,内置了完善的多线程支持,无需复杂配置即可快速实现并发编程。本教程将从基础概念、核心模块、实战案例、避坑指南四个维度,带你从零掌握 Python 多线程,轻松应对日常开发中的并发需求。
一、多线程核心概念:先搞懂这 3 个基础问题

  1. 什么是线程?
    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。简单来说:
    进程:一个运行的程序(比如打开的 Python 解释器、浏览器),拥有独立的内存空间;
    线程:进程中的执行分支,一个进程至少有一个主线程,可创建多个子线程,共享进程的内存空间。
    打个比方:进程是一家工厂,线程是工厂里的工人,工厂提供场地和设备(内存),多个工人可以同时干活(并发执行),效率更高。
  2. 什么是多线程?
    多线程就是在一个进程中同时运行多个线程,让程序能够并发处理多个任务。比如:
    视频软件:一边播放画面(线程 1),一边播放声音(线程 2),一边加载后续视频(线程 3);
    聊天软件:一边接收消息(线程 1),一边发送消息(线程 2),一边刷新好友列表(线程 3)。
  3. Python 多线程的特点:GIL 锁
    很多新手会问:Python 多线程真的能同时执行吗?这里需要了解GIL(全局解释器锁):
    GIL 是 CPython(Python 官方解释器)的机制,它确保同一时间只有一个线程执行 Python 字节码;
    因此,Python 多线程不适合 CPU 密集型任务(如大量计算),更适合I/O 密集型任务(如文件读写、网络请求、用户交互);
    I/O 密集型任务中,线程会频繁等待(如下载文件时等待网络响应),多线程可以充分利用等待时间,大幅提升效率。
    二、Python 多线程核心模块:threading
    Python3 中推荐使用threading 模块实现多线程,它替代了旧的 thread 模块,功能更完善、使用更安全。threading 模块提供了创建线程、管理线程、线程同步等核心功能,是 Python 多线程开发的必备工具。
  4. 线程的创建方式一:直接创建(最简单)
    通过threading.Thread类直接创建线程,传入需要执行的函数和参数,步骤如下:
    导入 threading 模块;
    定义需要并发执行的函数;
    创建 Thread 对象,指定 target(目标函数)和 args(函数参数);
    调用 start () 方法启动线程。
    代码示例:
    python
    运行
    import threading
    import time

定义需要执行的任务函数

def task(name, delay):
print(f"线程【{name}】启动,等待{delay}秒")
time.sleep(delay) # 模拟I/O等待(如网络请求、文件读写)
print(f"线程【{name}】执行完成")

if name == "main":
print("主线程启动")

# 创建线程1:执行task函数,参数为("线程1", 2)
t1 = threading.Thread(target=task, args=("线程1", 2))
# 创建线程2:执行task函数,参数为("线程2", 1)
t2 = threading.Thread(target=task, args=("线程2", 1))

# 启动线程
t1.start()
t2.start()

print("主线程结束")

运行结果:
plaintext
主线程启动
线程【线程1】启动,等待2秒
线程【线程2】启动,等待1秒
主线程结束
线程【线程2】执行完成
线程【线程1】执行完成
注意:start()是启动线程的关键,不能直接调用task()(否则是单线程执行)。

  1. 线程的创建方式二:继承 Thread 类(更灵活)
    当任务逻辑复杂时,可以通过继承 threading.Thread 类,重写run()方法实现线程,这种方式扩展性更强,适合封装复杂任务。
    代码示例:
    python
    运行
    import threading
    import time

自定义线程类,继承threading.Thread

class MyThread(threading.Thread):

# 初始化方法,接收参数
def __init__(self, name, delay):
    super().__init__()  # 调用父类构造方法
    self.name = name    # 线程名称
    self.delay = delay  # 等待时间

# 重写run方法:线程执行的核心逻辑
def run(self):
    print(f"线程【{self.name}】启动,等待{self.delay}秒")
    time.sleep(self.delay)
    print(f"线程【{self.name}】执行完成")

if name == "main":
print("主线程启动")

# 创建自定义线程对象
t1 = MyThread("线程1", 2)
t2 = MyThread("线程2", 1)

# 启动线程(自动调用run方法)
t1.start()
t2.start()

print("主线程结束")

运行结果与方式一一致,这种方式适合需要封装属性和方法的复杂场景。

  1. 线程常用方法:必须掌握
    threading 模块提供了多个管理线程的方法,日常开发高频使用:
    threading.Thread(target=函数, args=(参数,)):创建线程对象;
    start():启动线程(进入就绪状态,等待 CPU 调度);
    join([timeout]):主线程等待子线程执行完成,再继续执行;timeout 为可选等待时间(秒);
    is_alive():判断线程是否正在执行,返回 True/False;
    threading.current_thread():获取当前执行的线程对象;
    threading.active_count():获取当前活跃的线程数量。
    join () 方法实战:让主线程等待子线程完成再结束
    python
    运行
    import threading
    import time

def task(name, delay):
print(f"线程【{name}】启动")
time.sleep(delay)
print(f"线程【{name}】完成")

if name == "main":
t1 = threading.Thread(target=task, args=("线程1", 2))
t2 = threading.Thread(target=task, args=("线程2", 1))

t1.start()
t2.start()

# 主线程等待t1、t2执行完成
t1.join()
t2.join()

# 这行代码会在子线程全部完成后执行
print("所有线程执行完毕,主线程结束")

运行结果:
plaintext
线程【线程1】启动
线程【线程2】启动
线程【线程2】完成
线程【线程1】完成
所有线程执行完毕,主线程结束
三、线程同步:解决多线程资源竞争问题
多线程共享进程的内存空间,当多个线程同时修改同一个共享资源时,会出现数据混乱(资源竞争),这时候需要线程同步机制保证数据安全。

  1. 资源竞争问题演示
    python
    运行
    import threading

共享资源:全局变量

count = 0

def addcount():
global count
for
in range(100000):
count += 1 # 多个线程同时修改count

if name == "main":
t1 = threading.Thread(target=add_count)
t2 = threading.Thread(target=add_count)

t1.start()
t2.start()
t1.join()
t2.join()

# 预期结果:200000,实际结果小于200000
print(f"最终count值:{count}")

问题原因:count += 1不是原子操作(分为读取、修改、写入三步),多个线程交替执行时,会导致数据覆盖。

  1. 线程锁:Lock(互斥锁)解决竞争
    threading 模块提供Lock 锁,确保同一时间只有一个线程执行修改共享资源的代码,步骤:
    创建锁对象:lock = threading.Lock();
    加锁:lock.acquire();
    释放锁:lock.release()(必须释放,否则会造成死锁);
    推荐使用with语句(自动加锁、释放锁,避免死锁)。
    修复代码:
    python
    运行
    import threading

count = 0
lock = threading.Lock() # 创建互斥锁

def addcount():
global count
for
in range(100000):
with lock: # 自动加锁,代码块执行完自动释放锁
count += 1

if name == "main":
t1 = threading.Thread(target=add_count)
t2 = threading.Thread(target=add_count)

t1.start()
t2.start()
t1.join()
t2.join()

print(f"最终count值:{count}")  # 结果:200000,数据安全
  1. 死锁问题:必须避免
    死锁是指多个线程互相等待对方释放锁,导致程序卡住。比如:线程 1 持有锁 A,等待锁 B;线程 2 持有锁 B,等待锁 A,双方无限等待。
    避免死锁的原则:
    避免一个线程同时获取多个锁;
    避免一个线程在锁内占用多个资源;
    定时释放锁,不无限等待。
    四、多线程实战案例:I/O 密集型任务效率对比
    多线程最大的优势是提升 I/O 密集型任务的效率,我们通过模拟网络请求对比单线程和多线程的执行时间。
  2. 单线程执行
    python
    运行
    import time

模拟网络请求(I/O等待)

def request(url):
print(f"开始请求:{url}")
time.sleep(2) # 模拟2秒网络等待
print(f"请求完成:{url}")

if name == "main":
start = time.time()

# 依次请求3个网址
request("https://www.baidu.com")
request("https://www.google.com")
request("https://www.github.com")
end = time.time()
print(f"单线程总耗时:{end - start:.2f}秒")

运行结果:单线程总耗时≈6 秒(依次等待,2×3=6)

  1. 多线程执行
    python
    运行
    import threading
    import time

def request(url):
print(f"开始请求:{url}")
time.sleep(2)
print(f"请求完成:{url}")

if name == "main":
start = time.time()

# 创建3个线程
t1 = threading.Thread(target=request, args=("https://www.baidu.com",))
t2 = threading.Thread(target=request, args=("https://www.google.com",))
t3 = threading.Thread(target=request, args=("https://www.github.com",))

# 启动线程
t1.start()
t2.start()
t3.start()

# 等待所有线程完成
t1.join()
t2.join()
t3.join()

end = time.time()
print(f"多线程总耗时:{end - start:.2f}秒")

运行结果:多线程总耗时≈2 秒(并发执行,只等待一次 2 秒)
结论:I/O 密集型任务中,多线程效率是单线程的 N 倍(N 为线程数量),优势极其明显!
五、Python 多线程避坑指南(新手必看)
不要用多线程处理 CPU 密集型任务:GIL 锁限制,多线程无法并行计算,效率不如单线程,推荐用multiprocessing多进程;
线程不是越多越好:线程过多会导致 CPU 频繁切换线程(线程调度开销),反而降低效率,I/O 密集型任务一般设置 5-20 个线程即可;
共享资源必须加锁:多个线程修改同一变量、文件、数据库时,一定要用 Lock 锁保证数据安全;
守护线程:通过threading.Thread(daemon=True)设置守护线程,主线程退出时,守护线程会自动结束(适合后台任务);
避免死锁:严格控制锁的获取和释放,不用嵌套多个锁,不无限等待锁。
六、总结
Python 多线程是处理I/O 密集型任务的利器,核心知识点总结:
核心模块:threading,通过Thread类创建线程,start()启动,join()等待;
两种创建方式:直接传函数、继承 Thread 类;
线程同步:Lock 锁解决资源竞争,保证数据安全;
适用场景:网络请求、文件读写、用户交互、数据爬取等 I/O 密集型任务;
核心优势:充分利用 I/O 等待时间,大幅提升程序执行效率。
掌握本教程的内容,你已经可以独立完成 Python 多线程开发,应对日常工作中的并发需求。后续可以深入学习线程池(concurrent.futures.ThreadPoolExecutor)、信号量、事件等高级线程同步机制,让多线程编程更高效、更优雅!
参考:http://phdhk.cn

相关文章
|
2天前
|
人工智能 JSON 监控
Claude Code 源码泄露:一份价值亿元的 AI 工程公开课
我以为顶级 AI 产品的护城河是模型。读完这 51.2 万行泄露的源码,我发现自己错了。
3499 8
|
存储 文件存储 对象存储
块存储、文件存储和对象存储特点对比
块存储、文件存储和对象存储特点对比
1636 2
|
24天前
|
安全 Android开发 iOS开发
阿里云上的 Salesforce 安卓版移动端应用已上线!
阿里云上的 Salesforce 安卓版移动端应用已上线!
|
3月前
|
域名解析 网络协议 Linux
Linux网络基础完全指南(小白也能看懂的网络入门教程)
本教程系统讲解Linux网络基础,涵盖IP地址、子网掩码、网关、DNS等核心概念,介绍ifconfig、ip、ping等常用命令及网络配置文件的使用方法,助力掌握Linux网络配置技能。
426 117
|
2天前
|
数据采集 存储 供应链
数据架构怎么设计?一文全面掌握数据架构设计方法论
数据架构是连接业务与IT的桥梁,核心在于回答四个问题:企业有哪些数据?叫什么?什么关系?存在哪、如何流转?它涵盖数据资产目录、标准、模型、分布四大组件,以业务对象为管理单元,推动数据统一、可信、可管、可用。
|
2天前
|
人工智能 自然语言处理 安全
语音钓鱼(Vishing)统计特征、技术机理与全链路防御研究
本文基于SQ Magazine权威数据,系统分析2025—2026年语音钓鱼(Vishing)爆发式增长态势:AI语音克隆占比达42%,攻击频次半年激增442%,造成全球损失190亿美元。文章剖析号码仿冒、声纹克隆等技术机理,提出融合语义识别、声纹校验与行为检测的多维防御模型,并提供可工程化Python代码,构建覆盖终端、企业、运营商与监管的协同闭环体系。(239字)
30 5
|
2天前
|
Java 应用服务中间件 C++
Spring Boot 打包部署,JAR vs WAR
无论选择JAR还是WAR部署方式,关键在于匹配团队的技术栈、运维能力和业务需求。Spring Boot的灵活性支持两种部署模式,为不同场景提供了合适的解决方案。
66 4
|
2天前
|
SQL 运维 监控
税务季新型钓鱼攻击战术演进与企业全链路防御研究
本文剖析2026年税务季钓鱼攻击新趋势:滥用合法RMM工具实现持久化控制、W-2/W-8BEN表单欺诈及BEC复合攻击。基于Proofpoint情报,提出覆盖邮件网关、终端管控、身份认证、DLP与SOAR的全链路防御体系,并提供可落地的检测代码与规则。(239字)
32 4
|
2天前
|
人工智能 供应链 安全
邮件倦怠对小微企业网络钓鱼与欺诈风险的影响及防控研究
本文揭示邮件倦怠(如回避、仓促处理)正成为小微企业新型安全风险源,通过实证数据与攻击案例,阐明其如何削弱钓鱼识别、延缓告警响应、加剧BEC欺诈与数据泄露。提出“邮件治理+流程管控+技术防御+意识强化”四维轻量化防控体系,并附钓鱼检测代码与DMARC等实操配置,助力小微企业低成本提升邮件安全。(239字)
32 3
|
24天前
|
人工智能 搜索推荐 安全
生成式人工智能驱动下的诈骗范式转移与防御机制研究
本文剖析生成式AI驱动的新型网络诈骗趋势:钓鱼投诉激增85.6%,损失翻倍,攻击转向网络为主、多模态伪造。文章解构LLM钓鱼邮件生成与语音克隆技术,指出传统防御失效,并提出语义校验、多模态活体检测与动态信任链等主动防御架构。(239字)
193 10