Python 多线程详解(概念、初始化方式、线程间变量传递、线程锁以及一些注意事项)

Python 多线程详解

1. 多线程的概念

在 Python 中,多线程是指在一个进程内同时运行多个线程,以便在某些场景下提升程序的响应能力或并发性。

线程是 CPU 调度的最小单位,而进程是系统资源分配的最小单位。一个进程可以包含多个线程,这些线程共享同一进程的资源(包括内存空间)。

注意 :Python 的 GIL(Global Interpreter Lock,全局解释器锁) 限制了同一时刻只能有一个线程执行 Python 字节码 ,所以多线程在计算密集型任务中无法真正实现并行,更多用于 I/O 密集型任务(例如网络请求、文件读写)。


2. 多线程的初始化

在 Python 中可以使用 threading 模块来创建和管理线程。

2.1 使用 threading.Thread

python 复制代码
import threading
import time

def worker(name):
    print(f"线程 {name} 开始工作")
    time.sleep(1)
    print(f"线程 {name} 工作结束")

# 创建线程对象
t1 = threading.Thread(target=worker, args=("A",))
t2 = threading.Thread(target=worker, args=("B",))

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

# 等待线程结束
t1.join()
t2.join()

print("所有线程执行完毕")

关键参数

  • target:线程运行的函数。
  • args:传给函数的参数(元组形式)。
  • kwargs:传给函数的关键字参数。

3. 线程之间的变量传递

3.1 共享变量

线程之间可以共享同一个全局变量(因为它们在同一个进程中),但这会引发 数据竞争 问题。

python 复制代码
import threading

counter = 0  # 全局变量

def increment():
    global counter
    for _ in range(100000):
        counter += 1  # 多线程这里可能会出错

threads = []
for _ in range(5):
    t = threading.Thread(target=increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print("counter =", counter)

上面的代码可能不会得到想象的结果,因为多个线程同时修改 counter 会产生 竞态条件


4. 线程锁(Lock)

为避免数据竞争,我们需要使用 (Lock)来确保某段代码同一时刻只有一个线程能执行。

python 复制代码
import threading

counter = 0
lock = threading.Lock()

def safe_increment():
    global counter
    for _ in range(100000):
        with lock:  # 自动 acquire/release
            counter += 1

threads = []
for _ in range(5):
    t = threading.Thread(target=safe_increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print("counter =", counter)  # 结果正确

4.1 Lock 的用法

python 复制代码
lock = threading.Lock()

# 方式1
lock.acquire()
try:
    # 临界区代码
    pass
finally:
    lock.release()

# 方式2 (推荐)
with lock:
    # 临界区代码
    pass

5. 线程间通信

除了共享变量,还可以使用 队列(Queue) 来安全地进行线程间数据传递。

python 复制代码
import threading
import queue
import time

q = queue.Queue()

def producer():
    for i in range(5):
        q.put(i)
        print(f"生产数据 {i}")
        time.sleep(0.2)

def consumer():
    while True:
        item = q.get()
        if item is None:  # 遇到 None 退出
            break
        print(f"消费数据 {item}")
        time.sleep(0.3)
        q.task_done()

t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)

t1.start()
t2.start()

t1.join()
q.put(None)  # 通知消费者退出
t2.join()

优点queue.Queue() 是线程安全的,内部已经做好了加锁处理,无需手动使用 Lock。


6. 守护线程(Daemon Thread)

守护线程会在主线程结束时自动退出。

python 复制代码
t = threading.Thread(target=worker)
t.daemon = True  # 设为守护线程
t.start()

适合做后台任务,例如日志记录或心跳检测。


7. 线程池(ThreadPoolExecutor)

如果需要频繁创建和销毁线程,可以使用线程池来提升性能。

python 复制代码
from concurrent.futures import ThreadPoolExecutor

def task(name):
    print(f"{name} 开始")
    return f"{name} 完成"

with ThreadPoolExecutor(max_workers=3) as executor:
    futures = [executor.submit(task, f"任务{i}") for i in range(5)]
    for future in futures:
        print(future.result())

8. 总结与建议

  • 计算密集型任务 :推荐使用多进程(multiprocessing)而不是多线程,避免 GIL 限制。
  • I/O 密集型任务 :推荐使用多线程或异步(asyncio)。
  • 使用 LockQueue 解决数据竞争和线程安全问题。
  • 合理规划线程数量,不要盲目创建过多线程。
  • 可以用 ThreadPoolExecutor 简化线程管理。
相关推荐
jay神1 小时前
2026年YOLO还有哪些创新点可以做?
python·yolo·毕业设计·科研·课程设计·创新
傲笑风10 小时前
【openvino】tinybert基于openvino服务化部署(四)
人工智能·python·自然语言处理·nlp·bert·openvino
维基框架10 小时前
WIKI 知识库 v1.1.1 正式发布
人工智能·python
谢白羽14 小时前
SGLang的AWQ量化笔记
笔记·python·sglang
迷迭香yy14 小时前
基金档案数据工程实战从收入分析到持仓穿透的Python解析 IG50免费开源股票数据API接口
开发语言·python
清水白石00814 小时前
Python 类型设计深度解析:TypedDict 能否替代 dataclass?从 JSON 数据边界到 API 设计的最佳实践
java·python·json
️学习的小王15 小时前
Git项目提交忽略文件怎么做?以Python项目为例,详解.gitignore
git·python·elasticsearch
前端 贾公子15 小时前
第09章:上下文与记忆 (6)
开发语言·前端·python
evans在进步15 小时前
Java 常用设计模式入门:建造者、工厂、单例、外观与代理
java·python·设计模式
jayson.h16 小时前
PDF 合并+添加页码 相关库、类、函数
开发语言·前端·python