page contents

python面试题:什么是多线程竞争?

这个问题在 Python 面试里经常出现,面试官一开口问“你了解多线程竞争吗?”我心里就开始犯嘀咕:你是想问我线程安全吗,还是想看我有没有被 GIL 折腾疯?不过不慌,我们今天就掰扯清楚这事儿。

attachments-2025-09-u8ZCfmgb68cb60e27ce4d.png这个问题在 Python 面试里经常出现,面试官一开口问“你了解多线程竞争吗?”我心里就开始犯嘀咕:你是想问我线程安全吗,还是想看我有没有被 GIL 折腾疯?不过不慌,我们今天就掰扯清楚这事儿。

所谓“多线程竞争”(Race Condition),简单来说就是:多个线程在没有同步机制的前提下,同时访问和修改某个共享资源,导致程序运行结果不可预期,甚至崩掉。

说得再通俗点,就是好几个熊孩子一起抢玩具,还不排队,那现场就乱套了。

举个栗子:抢票系统中的“惊喜”

假设你搞了个抢票功能,线程1和线程2几乎同时读取了剩余票数,然后都判断还有票,然后都卖出了一张——结果本来只剩一张票,现在卖出两张,你想想乘客在车厢里互相对视的场景吧,热闹得很。

看段代码你就知道问题出在哪了:

import threading

tickets = 1

def sell_ticket():
    global tickets
    if tickets > 0:
        print(f"{threading.current_thread().name} 抢到票了!")
        tickets -= 1
    else:
        print(f"{threading.current_thread().name} 没票了...")

threads = []
for i in range(2):
    t = threading.Thread(target=sell_ticket, name=f"线程-{i+1}")
    threads.append(t)
    t.start()

for t in threads:
    t.join()

你以为这玩意儿会严格一个抢到,一个抢不到?不一定。因为这段代码没有加锁,两个线程可能几乎同时读取到 tickets = 1,然后都认为自己可以减1,然后都减了,就变成了 -1……

Python 的 GIL 就能解决多线程竞争吗?

我一度也天真地以为,Python 有 GIL(全局解释器锁),多线程就不用操心线程安全了。

天真了,兄弟。

GIL 确实让某一时刻只有一个线程在执行 Python 字节码,但这并不代表线程间访问共享资源就安全了。比如执行 tickets -= 1,这是三个操作(读取、减一、写回),不是原子操作,中间是可能被打断的。所以GIL不能保证线程安全

想让上面的例子变得线程安全,我们得老老实实加锁:

lock = threading.Lock()

def sell_ticket_safe():
    global tickets
    with lock:
        if tickets > 0:
            print(f"{threading.current_thread().name} 抢到票了!")
            tickets -= 1
        else:
            print(f"{threading.current_thread().name} 没票了...")

使用 with lock: 就像在资源外面装了一个门禁卡,没刷卡就进不来,线程只能一个一个进来修改 tickets,就不怕抢破头了。

多线程竞争都能用锁解决吗?

理论上可以,实践中呢?加锁加多了,性能就下来了,而且容易出现死锁问题。比如你线程A拿了资源1,等资源2,线程B拿了资源2,等资源1……两人互相等着,就跟电梯里两个躲避社死的人一样,你进我退,我进你又退,最后谁也进不去。

这也是为什么很多人更倾向于用多进程而不是多线程,或者直接上协程来规避这些问题。

我觉得面试问这个问题其实在探啥?

我遇到过的面试官,一般问“什么是多线程竞争”其实不光是想你定义标准答案,他们是想听你有没有意识到线程安全的问题,有没有实际场景的经验,会不会使用锁或者其他同步机制。

你可以说出“资源竞争”、“共享资源”、“非原子性”、“加锁解决”,甚至加点自己踩过的坑,都是加分项。

比如我自己就因为在用 Queue 的时候偷懒没加锁,结果日志记录顺序乱成一锅粥,查 bug 查了三天,最后发现问题出在用了非线程安全的数据结构。

总结下坑点(就事论事,不总结文章)

  • • Python 有 GIL,但不等于线程安全。
  • • 多线程竞争一般发生在对共享资源的并发读写。
  • • 解决方法最常见的是加锁(threading.Lock()),但要注意性能和死锁问题。
  • • 如果资源竞争太激烈,考虑多进程或者异步编程。
  • • 面试中提到这个,关键是展示你对并发问题的理解,不是背定义。

你要是再碰上这个面试题,别慌,先确认面试官说的是线程间的资源争用,然后像讲故事一样,把你写抢票系统踩过的坑讲出来,再说怎么加锁,最后再补一句“Python 有 GIL 但还得靠自己保护资源”,面试官基本就满意了。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1368 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2200 文章
  3. Pack 1370 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章