news 2026/4/18 12:28:38

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 多线程详解(概念、初始化方式、线程间变量传递、线程锁以及一些注意事项)

Python 多线程详解

1. 多线程的概念

在 Python 中,多线程是指在一个进程内同时运行多个线程,以便在某些场景下提升程序的响应能力或并发性。
线程是 CPU 调度的最小单位,而进程是系统资源分配的最小单位。一个进程可以包含多个线程,这些线程共享同一进程的资源(包括内存空间)。

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


2. 多线程的初始化

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

2.1 使用threading.Thread

importthreadingimporttimedefworker(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 共享变量

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

importthreading counter=0# 全局变量defincrement():globalcounterfor_inrange(100000):counter+=1# 多线程这里可能会出错threads=[]for_inrange(5):t=threading.Thread(target=increment)threads.append(t)t.start()fortinthreads:t.join()print("counter =",counter)

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


4. 线程锁(Lock)

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

importthreading counter=0lock=threading.Lock()defsafe_increment():globalcounterfor_inrange(100000):withlock:# 自动 acquire/releasecounter+=1threads=[]for_inrange(5):t=threading.Thread(target=safe_increment)threads.append(t)t.start()fortinthreads:t.join()print("counter =",counter)# 结果正确

4.1Lock的用法

lock=threading.Lock()# 方式1lock.acquire()try:# 临界区代码passfinally:lock.release()# 方式2 (推荐)withlock:# 临界区代码pass

5. 线程间通信

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

importthreadingimportqueueimporttime q=queue.Queue()defproducer():foriinrange(5):q.put(i)print(f"生产数据{i}")time.sleep(0.2)defconsumer():whileTrue:item=q.get()ifitemisNone:# 遇到 None 退出breakprint(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)

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

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

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


7. 线程池(ThreadPoolExecutor)

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

fromconcurrent.futuresimportThreadPoolExecutordeftask(name):print(f"{name}开始")returnf"{name}完成"withThreadPoolExecutor(max_workers=3)asexecutor:futures=[executor.submit(task,f"任务{i}")foriinrange(5)]forfutureinfutures:print(future.result())

8. 总结与建议

  • 计算密集型任务:推荐使用多进程(multiprocessing)而不是多线程,避免 GIL 限制。
  • I/O 密集型任务:推荐使用多线程或异步(asyncio)。
  • 使用LockQueue解决数据竞争和线程安全问题。
  • 合理规划线程数量,不要盲目创建过多线程。
  • 可以用ThreadPoolExecutor简化线程管理。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 6:24:00

基于Multisim仿真电路图的运算放大器完整指南

从零开始掌握运放设计:用Multisim搭建你的第一块“虚拟电路板”你有没有过这样的经历?花了一整天时间在面包板上搭好一个放大电路,结果示波器一接上去——输出全是噪声,甚至直接饱和了。换电阻、调电源、查接线……折腾半天才发现…

作者头像 李华
网站建设 2026/4/18 6:24:30

火车轨道线检测数据集5928张VOC+YOLO格式

火车轨道线检测数据集5928张VOCYOLO格式数据集格式:VOC格式YOLO格式压缩包内含:3个文件夹,分别存储图片、xml、txt文件JPEGImages文件夹中jpg图片总计:5928Annotations文件夹中xml文件总计:5928labels文件夹中txt文件总…

作者头像 李华
网站建设 2026/4/18 5:25:24

利用Anything-LLM+GPU算力实现高性能语义检索

利用 Anything-LLM 与 GPU 算力构建高性能语义检索系统 在企业知识爆炸式增长的今天,一个常见的尴尬场景是:IT 员工翻遍了几十份技术文档,却仍找不到某项 API 接口变更的具体说明;法务人员面对上千页合同,难以快速定位…

作者头像 李华
网站建设 2026/4/18 6:24:12

医疗、法律等行业如何利用Anything-LLM保护数据隐私?

医疗、法律等行业如何利用Anything-LLM保护数据隐私? 在医院的深夜值班室里,一位年轻医生面对一名突发过敏反应的患儿,急需确认肾上腺素的使用剂量和禁忌症。他没有翻找厚重的诊疗手册,也没有冒险在公共搜索引擎中输入敏感关键词&…

作者头像 李华
网站建设 2026/4/18 8:37:49

智能小车PCB板原理图多层板设计注意事项

智能小车PCB设计实战:从原理图到多层板的系统级思考最近在调试一款用于教学竞赛的智能小车控制板时,遇到了一个典型问题:电机一启动,主控芯片就复位。示波器抓了一下电源引脚,发现每次PWM调速瞬间,VDD上都有…

作者头像 李华
网站建设 2026/4/18 6:23:39

Vivado仿真核心要点:初始化输入激励的正确方式

Vivado仿真避坑指南:输入激励初始化的正确打开方式你有没有遇到过这样的情况?写好了一个状态机,信心满满地跑Vivado仿真,结果波形图里满屏都是红红的X,输出永远不跳变,状态机像“卡死”了一样毫无反应。查了…

作者头像 李华