网站首页 > 技术文章 正文
在当今这个多任务处理的时代,让程序能够"同时"做多件事情变得越来越重要。threading库就是Python中实现多线程编程的利器。
一、什么是线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。简单来说:
- 一个进程可以包含多个线程
- 线程共享进程的内存空间
- 线程比进程更轻量,创建和切换开销更小
https://example.com/thread_vs_process.png
二、为什么需要多线程?
想象一下你在厨房做饭:
- 单线程:先烧水,水开了再切菜,然后炒菜——效率低下
- 多线程:一边烧水一边切菜——效率大大提高
在程序中,多线程特别适合I/O密集型任务,比如:
- 网络请求
- 文件读写
- 数据库操作
三、threading基础用法
1. 创建线程
Python的threading模块提供了Thread类来创建和管理线程。看个简单例子:
import threading
import time
def task(name):
print(f"任务 {name} 开始")
time.sleep(2) # 模拟耗时操作
print(f"任务 {name} 完成")
# 创建线程
t1 = threading.Thread(target=task, args=("A",))
t2 = threading.Thread(target=task, args=("B",))
# 启动线程
t1.start()
t2.start()
# 等待线程结束
t1.join()
t2.join()
print("所有任务完成")
输出可能是:
任务 A 开始
任务 B 开始
(约2秒后)
任务 A 完成
任务 B 完成
所有任务完成
2. 线程的生命周期
- 新建:创建Thread对象
- 就绪:调用start()后
- 运行:被调度器选中
- 阻塞:遇到I/O操作或sleep等
- 终止:run()方法执行完毕
四、线程同步
当多个线程共享数据时,可能会产生竞争条件。threading提供了多种同步机制:
1. Lock(锁)
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
lock.acquire() # 获取锁
counter += 1
lock.release() # 释放锁
threads = []
for _ in range(5):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"最终计数器值: {counter}") # 应该是500000
2. RLock(可重入锁)
同一个线程可以多次acquire同一个RLock
rlock = threading.RLock()
def func():
with rlock: # 第一次获取锁
with rlock: # 第二次获取同一个锁
print("成功获取锁")
3. Condition(条件变量)
用于线程间的通信
import threading
def consumer(cond):
with cond:
print("消费者等待中...")
cond.wait() # 等待通知
print("消费者收到通知,继续执行")
def producer(cond):
with cond:
print("生产者准备通知")
cond.notifyAll() # 通知所有等待的线程
print("已通知")
condition = threading.Condition()
t1 = threading.Thread(name='consumer', target=consumer, args=(condition,))
t2 = threading.Thread(name='producer', target=producer, args=(condition,))
t1.start()
t2.start()
t1.join()
t2.join()
五、线程池ThreadPoolExecutor
Python 3.2+引入了concurrent.futures模块,提供了更高级的线程池接口:
from concurrent.futures import ThreadPoolExecutor
import time
def task(n):
time.sleep(1)
return n * n
with ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(task, i) for i in range(5)]
for future in concurrent.futures.as_completed(futures):
print(future.result())
六、线程的局限性
需要注意的是,由于Python的GIL(全局解释器锁),多线程在CPU密集型任务上并不能真正并行执行。对于CPU密集型任务,建议使用multiprocessing模块。
七、实际应用案例
1. 多线程下载文件
import threading
import requests
def download(url, filename):
print(f"开始下载 {filename}")
response = requests.get(url, stream=True)
with open(filename, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"{filename} 下载完成")
urls = [
("https://example.com/file1.zip", "file1.zip"),
("https://example.com/file2.zip", "file2.zip"),
("https://example.com/file3.zip", "file3.zip")
]
threads = []
for url, filename in urls:
t = threading.Thread(target=download, args=(url, filename))
t.start()
threads.append(t)
for t in threads:
t.join()
print("所有文件下载完成")
2. 生产者-消费者模型
import threading
import queue
import random
import time
def producer(q, name):
for i in range(5):
item = f"{name}-产品{i}"
q.put(item)
print(f"{name} 生产了 {item}")
time.sleep(random.random())
def consumer(q, name):
while True:
item = q.get()
if item is None: # 终止信号
break
print(f"{name} 消费了 {item}")
time.sleep(random.random() * 2)
q.task_done()
q = queue.Queue()
producers = []
consumers = []
# 创建2个生产者
for i in range(2):
p = threading.Thread(target=producer, args=(q, f"生产者{i}"))
p.start()
producers.append(p)
# 创建3个消费者
for i in range(3):
c = threading.Thread(target=consumer, args=(q, f"消费者{i}"))
c.start()
consumers.append(c)
# 等待生产者完成
for p in producers:
p.join()
# 发送终止信号给消费者
for _ in consumers:
q.put(None)
# 等待消费者完成
for c in consumers:
c.join()
print("生产消费结束")
八、线程最佳实践
- 避免使用全局变量:线程间共享数据容易引发竞争条件
- 合理使用锁:锁会降低性能,只在必要时使用
- 避免死锁:确保锁总是能被释放(使用with语句)
- 控制线程数量:太多线程会导致上下文切换开销增大
- 考虑使用队列:queue模块提供了线程安全的队列实现
九、总结
Python的threading模块为多线程编程提供了强大的支持,特别适合I/O密集型任务。通过合理使用线程同步机制,我们可以构建高效、可靠的多线程应用。不过也要记住它的局限性,在CPU密集型任务中考虑使用多进程。
- 上一篇: 用栈-stack实现队列queue-LeetCode
- 下一篇: 消息队列的测试方法
猜你喜欢
- 2025-08-06 生产环境中使用的十大 Python 设计模式
- 2025-08-06 面试必备:Python内存管理机制(建议收藏)
- 2025-08-06 服务端开发面试必背——消息队列及它的主要用途和优点。附代码
- 2025-08-06 Python 栈:深度解析与应用
- 2025-08-06 Python中的多进程
- 2025-08-06 Python Logging 最佳实践
- 2025-08-06 Python并发数据结构实现原理
- 2025-08-06 用SendGrid和Redis队列用Python调度国际空间站的电子邮件
- 2025-08-06 Python教程(三十五):数据库操作进阶
- 2025-08-06 Python倒车请注意!负步长range的10个高能用法,让代码效率翻倍
- 08-06生产环境中使用的十大 Python 设计模式
- 08-06面试必备:Python内存管理机制(建议收藏)
- 08-06服务端开发面试必背——消息队列及它的主要用途和优点。附代码
- 08-06Python 栈:深度解析与应用
- 08-06Python中的多进程
- 08-06Python Logging 最佳实践
- 08-06Python并发数据结构实现原理
- 08-06用SendGrid和Redis队列用Python调度国际空间站的电子邮件
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)