大家好,欢迎来到IT知识分享网。
点赞、收藏、加关注,下次找我不迷路
不管你是刚入行的新手,还是有一定经验的开发者,掌握多线程的核心问题,都能让你在面试中脱颖而出。今天咱就来盘一盘 5 个高频的 Python 多线程面试题,用通俗易懂的语言解释,让你轻松弄懂,记得拿小本本记好哦!

一、线程和进程的区别是啥?(基础必考题)
问题抛出
考官一上来可能就会问:”说说线程和进程的区别吧。” 好多新手听到这个问题,脑子一下子就懵圈了,这俩到底啥关系,又有啥不一样呢?
白话解释
咱打个比方,把计算机比作一个大公司。进程就像是公司里的各个部门,比如研发部、销售部、财务部。每个部门都有自己独立的资源,像研发部有自己的电脑、资料、办公用品,销售部也有自己的一套东西,部门之间是相互隔离的,互不干扰。而线程呢,就好比部门里的员工。一个部门里可以有多个员工,这些员工共享部门的资源,比如同一台打印机、同一个文件服务器。员工之间可以协作完成任务,但如果协作不好,也可能会出问题,比如两个员工同时修改同一个文件,就会产生冲突。
举例说明
比如说,你同时打开了一个 Word 文档(这是一个进程)和一个浏览器(这又是一个进程)。Word 进程有自己的内存空间、文件句柄等资源,浏览器进程也有自己独立的一套。而在 Word 进程里,可能有一个线程负责显示文字,一个线程负责处理键盘输入,这两个线程共享 Word 进程的资源。
答案总结
对比项 |
进程 |
线程 |
定义 |
资源分配的最小单位 |
CPU 调度的最小单位 |
资源 |
独立拥有资源 |
共享所属进程的资源 |
开销 |
创建、销毁开销大 |
创建、销毁开销小 |
并发性 |
进程间并发 |
同一进程内线程间并发 |
健壮性 |
一个进程崩溃不影响其他进程 |
一个线程崩溃可能导致整个进程崩溃 |
记忆诀窍
“进程像部门,资源各自管;线程如员工,共享资源干。”
二、Python 里的 GIL 是啥?为啥有 GIL 还能说支持多线程?(灵魂拷问)
问题抛出
“听说过 GIL 吗?它对多线程有啥影响?为啥 Python 有 GIL 还支持多线程呢?” 这个问题可太关键了,很多人对 GIL 一知半解,面试时很容易栽跟头。
白话解释
GIL 就是全局解释器锁,说白了,就是 Python 解释器为了保证线程安全,搞的一个 “枷锁”。在同一时间,这个锁只能被一个线程持有,也就是说,即使你的电脑是多核 CPU,同一时间也只能有一个线程在执行 Python 字节码。这就好比一群人要过一个狭窄的独木桥,一次只能过一个人,其他人都得在旁边等着。那为啥 Python 还有多线程呢?虽然 GIL 限制了 CPU 密集型任务的并行执行,但对于 IO 密集型任务,比如读写文件、网络请求,线程在等待 IO 的时候,会释放 GIL,让其他线程去执行,这样就提高了效率。
举例说明
比如你有两个任务,一个是计算 1 到 1 亿的和(CPU 密集型),一个是从网上下载两个大文件(IO 密集型)。如果用多线程来执行计算任务,因为 GIL 的存在,两个线程只能轮流执行,速度并不会比单线程快多少。但如果是下载文件,当一个线程在等待网络响应时,会释放 GIL,另一个线程就可以开始下载,这样整体时间就会缩短。
答案总结
GIL 是 Python 解释器中的一个全局锁,确保同一时间只有一个线程执行字节码。对于 CPU 密集型任务,多线程由于 GIL 的存在,无法真正利用多核优势,效率可能不如单线程;对于 IO 密集型任务,线程在等待 IO 时释放 GIL,其他线程可以利用这个时间执行,从而提高效率。所以 Python 的多线程在 IO 密集型场景下是有用的,这也是它支持多线程的原因。
记忆诀窍
“GIL 是把锁,线程轮流走;CPU 任务愁,IO 任务牛。”
三、Python 中创建线程的方式有哪些?怎么用?(实操题)
问题抛出
“说说 Python 里创建线程的方法吧,最好能写个例子。” 这可是考察你实际操作能力的问题,得把步骤说清楚。
白话解释
Python 里主要有两种创建线程的方式,一种是通过 threading 模块的 Thread 类,直接创建线程对象,然后传入目标函数;另一种是继承 Thread 类,重写 run 方法,把要执行的代码放在 run 方法里。就好比你要让工人干活,一种是直接告诉工人去做某个具体的任务(目标函数),另一种是给工人定制一个专属的任务类,让他按照类里的步骤去做。
举例说明
方式一:使用 threading.Thread 创建线程
import threading import time # 定义目标函数 def my_task(name, seconds): print(f"线程{name}开始执行") time.sleep(seconds) print(f"线程{name}执行结束") # 创建线程对象 thread1 = threading.Thread(target=my_task, args=("线程1", 2)) thread2 = threading.Thread(target=my_task, args=("线程2", 3)) # 启动线程 thread1.start() thread2.start() # 等待线程结束 thread1.join() thread2.join()
方式二:继承 threading.Thread 类
import threading import time class MyThread(threading.Thread): def __init__(self, name, seconds): super().__init__(name=name) self.seconds = seconds def run(self): print(f"线程{self.name}开始执行") time.sleep(self.seconds) print(f"线程{self.name}执行结束") # 创建线程实例 thread1 = MyThread("线程1", 2) thread2 = MyThread("线程2", 3) # 启动线程 thread1.start() thread2.start() # 等待线程结束 thread1.join() thread2.join()
方式三:面试官问还有么?
那这家公司咱就不去了,哈哈。
答案总结
创建方式 |
步骤 |
特点 |
适用场景 |
Thread 类创建 |
1. 定义目标函数; 2. 创建 Thread 对象,传入目标函数和参数; 3. 调用 start () 启动线程 |
简单直接,适合简单任务 |
快速创建单个或多个独立任务线程 |
继承 Thread 类 |
1. 定义子类继承 Thread; 2. 重写 run 方法; 3. 创建子类实例,调用 start () 启动 |
可以封装更多线程相关的属性和方法 |
需要为线程定制复杂功能或维护线程状态 |
记忆诀窍
“创建线程两招鲜,目标函数或继承;简单任务用前者,复杂定制后者行。”
四、多线程中为什么需要线程同步?怎么实现?(重点应用题)
问题抛出
“多线程中线程同步是什么?为啥需要它?怎么实现呢?” 这涉及到多线程编程的核心难点,必须搞清楚。
白话解释
线程同步就是让多个线程按照一定的顺序执行,避免出现数据不一致的问题。比如多个线程同时修改一个共享的变量,如果不加控制,就会导致结果混乱。就像两个人同时去修改一个账本,你改一笔,我改一笔,最后账本就乱了,不知道到底哪个是正确的。这时候就需要一把 “锁”,让一个线程在修改的时候,其他线程不能修改,等这个线程改完了,再释放锁,让其他线程来改。
举例说明
假设我们有一个银行账户,两个线程同时往这个账户里存钱,每次存 100 元,一共存 100 次。如果没有线程同步,可能会出现这样的情况:线程 1 读取当前余额是 0,准备加上 100;这时候线程 2 也读取当前余额是 0,也准备加上 100。然后两个线程都把余额写成 100,这样实际上只存了一次,却记录了两次,导致余额错误。加上锁之后,线程 1 在读取和修改余额的时候,锁住这个账户,线程 2 只能等待,等线程 1 改完释放锁,线程 2 再去操作,这样就不会出错了。
答案总结
线程同步是为了保证多个线程对共享资源的访问是有序的,避免数据不一致。实现线程同步的方法主要有以下几种:
- 锁(Lock):最基本的同步机制,获取锁的线程执行完操作后释放锁,其他线程才能获取锁。
- RLock(可重入锁):同一个线程可以多次获取同一个锁,避免死锁,比如在一个函数里多次调用加锁的方法。
- 信号量(Semaphore):控制同时访问资源的线程数量,比如限制最多 3 个线程同时访问某个文件。
- 事件(Event):用于线程之间的通信,一个线程设置事件,其他线程等待事件触发。
记忆诀窍
“线程同步很重要,共享资源别乱搞;锁、信号量、事件,按需选择错不了。”
五、什么是守护线程?怎么设置?有啥用?(细节题)
问题抛出
“守护线程了解吗?怎么设置?它和非守护线程有啥区别?” 这是一个考察细节的问题,很多人可能忽略这个点。
白话解释
守护线程就像是一个 “保镖” 线程,它的作用是为其他线程提供服务。当所有非守护线程都结束时,守护线程会自动终止,不管它有没有完成任务。比如你在下载文件的时候,有一个守护线程在后台监控网络连接,当下载主线程结束后,这个监控线程也会跟着结束。设置守护线程很简单,只需要在创建线程后,调用 setDaemon (True) 方法就行。
举例说明
比如我们有一个主线程,创建了一个守护线程来定期清理临时文件。当主线程运行结束后,不管清理任务有没有完成,守护线程都会被终止。如果不设置守护线程,主线程结束后,还得等待这个清理线程完成才能真正退出。
答案总结
守护线程是在后台运行的线程,用于为其他线程提供服务。设置守护线程的方法是在线程启动前调用 setDaemon (True) 或者在创建线程时传入 daemon=True 参数。守护线程的特点是:当所有非守护线程结束时,守护线程会自动终止,不会阻塞程序的退出。它的主要用途是执行一些辅助性的任务,比如日志记录、资源监控等。
记忆诀窍
“守护线程像保镖,服务他人不傲娇;主线程完它就走,设置 daemon 要记牢。”
来个对比,让你一目了然
面试题 |
核心考点 |
答案要点 |
记忆诀窍 |
线程和进程的区别 |
定义、资源、开销、并发性 |
进程资源独立,线程共享资源;进程开销大,线程开销小 |
进程像部门,线程如员工 |
GIL 是什么?为啥有 GIL 还支持多线程? |
GIL 原理、对多线程的影响 |
GIL 是全局锁,限制 CPU 密集型任务并行;IO 密集型任务中线程等待 IO 时释放 GIL |
GIL 是把锁,CPU 愁 IO 牛 |
创建线程的方式 |
Thread 类、继承 Thread 类 |
两种方式的步骤和特点 |
目标函数或继承,简单复杂各不同 |
线程同步 |
原因、实现方法 |
避免共享资源混乱,用锁、信号量等实现 |
线程同步靠锁,共享资源保护好 |
守护线程 |
定义、设置、作用 |
后台服务线程,随非守护线程结束而终止 |
守护线程像保镖,daemon 设置不能少 |
只要你把这些内容吃透,面试的时候肯定能对答如流。赶紧把文章收藏起来,多复习几遍,说不定下一个拿到高薪 offer 的就是你!如果还有其他 Python 问题,欢迎在评论区留言,咱们一起讨论学习!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/180213.html