首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

关于 Python 多线程的一个疑问,见笑!

  •  
  •   xianhu · 135 天前 · 2025 次点击
    这是一个创建于 135 天前的主题,其中的信息可能已经有所发展或是发生改变。
    既然 Python 的多线程模式是伪多线程,即同一时刻只能有一个线程执行。那么为什么还会有 threading.Queue 这种所谓线程安全的变量类型呢?我理解应该任何数据类型( list、tuple 等)都是线程安全的。
    有谁可以给解释一下吗?
    25 回复  |  直到 2019-07-27 09:30:59 +08:00
        1
    cigarzh   135 天前 via iPhone
    i += 1
        2
    xianhu   135 天前
    @cigarzh 感谢。通过一通试验之后,我貌似明白了。
        3
    CEBBCAT   135 天前 via Android
    原子操作吗? 看了前两楼还是没太懂
        4
    ctrlaltdeletel   135 天前
    同一时刻只能有一个线程执行指的是 byte code 级别的执行,一个包含多个 byte code 的函数中仍有可能会发生线程调度的
        5
    jingxyy   135 天前
    就是原子性问题呗 虽然有 gil 但你想象一个场景 比如你对 list 做 append append 要做好几个操作 某个线程做了一部分的操作 然后切到另一个线程再做 append 这会有啥后果
        6
    bantao   135 天前
    cpu 支持并发,达到某些条件会线程切换,Python 因为 GIL 而不支持真正的并行,GIL 同一时刻( cpu 时间片)只允许一个线程,不是在一段时间内只允许一个线程执行。所以线程不安全的变量,在多线程环境中,可能在变量并未发生变化时,就被切换到另外一个线程中被使用了。https://www.zhihu.com/question/23030421
        7
    xianhu   135 天前
    @jingxyy 真巧,针对这个场景,我刚刚用代码跑了一下 [启动 4 个线程,一个全局的 list 变量,每个线程都对这个 list 进行 append 操作 100000 次] 。跑完之后,对于这个 list 的长度没什么影响,里边的元素值也没什么影响,只是对元素的排列顺序有影响。
        8
    xianhu   135 天前
    @xianhu 把这个实验中的 list 改为一个 int 值,每个线程对这个值进行+1 操作 100000 次,最终查看结果,发现值对不上。这就是 1 楼 i += 1 的意思。
        9
    jingxyy   135 天前
    @xianhu
    这样吗(翻车了……
    回头看看 list 底层有什么魔法
        10
    wwqgtxx   135 天前   ♥ 1
    @jingxyy @xianhu python 官方文档提到了在 cpython 的实现中 list 的 append 是原子的
    https://docs.python.org/3.7/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
        11
    wwqgtxx   135 天前
    其实一个操作是不是原子的有两种评判标准:
    1、对于纯 Python 代码,是不是只有一条 byte code
    2、对于 C 实现的函数,内部有没有释放 GIL
        12
    hhhsuan   135 天前 via Android
    忘了 Python 线程吧,直接用进程
        13
    whoami9894   135 天前
    @hhhsuan 不是 CPU 密集运算干嘛用多进程? I/O 操作的单核线程并发相比进程开销要高效的多
        14
    Hopetree   135 天前
    @hhhsuan 你用过 python 吗?知道什么时候用线程什么时候用进程吗?不知道就别乱说
    还有,那些喜欢拿 python 的 GIL 说事情的人麻烦好好看看自己的代码有没有资格被 GIL 影响
        15
    wwqgtxx   135 天前
    @hhhsuan 多进程来传递个 FD 看能不能把你搞疯掉
        16
    bilibilifi   134 天前 via iPhone
    @whoami9894 感觉 python 的 multprocessing 确实有黑科技,试过把主 loop 用 prange 重写只快了百分之 30
        17
    jingxyy   134 天前
    @wwqgtxx
    原来如此 感谢
        18
    oahebky   134 天前
    用 C 语言写的多线程在十几二十年前的单核 CPU 的电脑上运行,需不需要保证线程安全呢???
    (同理,用其它语言写多线程在单核 CPU 上运行需不需要保证线程安全呢?)

    现在搞不清楚也没关系,多看书,看看名校公开课,写写代码,逐渐就有概念了。
        19
    cwjokaka   134 天前
    因为多线程之间会进行上下文切换,执行非原子操作的时候可能在过程中挂起当前线程,之后继续执行的的时数据可能已不是最新了
        20
    xianhu   134 天前
    @wwqgtxx 感谢。
        21
    hhhsuan   134 天前
    @Hopetree #14 我没用过,谢谢
        22
    hhhsuan   134 天前
    @wwqgtxx #15 传 fd 本身就是糟糕的设计,即便是线程也要尽量避免。
        23
    wwqgtxx   134 天前 via iPhone
    @hhhsuan 作为一个 web server,跨线程传递一个 socket fd 是非常参见的
        24
    wwqgtxx   134 天前 via iPhone
    @hhhsuan 在保证一个 fd 只会被一个线程操作的情况下,传递 fd 没有任何糟糕的,如果你觉得糟糕,那只能说明你程序写的烂
        25
    hhhsuan   133 天前
    @wwqgtxx #24 你说得对,我写的烂
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   918 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 20:10 · PVG 04:10 · LAX 12:10 · JFK 15:10
    ♥ Do have faith in what you're doing.