V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
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
xianhu
V2EX  ›  Python

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

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

    现在搞不清楚也没关系,多看书,看看名校公开课,写写代码,逐渐就有概念了。
    cwjokaka
        19
    cwjokaka  
       2019-07-26 10:02:51 +08:00
    因为多线程之间会进行上下文切换,执行非原子操作的时候可能在过程中挂起当前线程,之后继续执行的的时数据可能已不是最新了
    xianhu
        20
    xianhu  
    OP
       2019-07-26 10:22:29 +08:00
    @wwqgtxx 感谢。
    hhhsuan
        21
    hhhsuan  
       2019-07-26 10:25:49 +08:00
    @Hopetree #14 我没用过,谢谢
    hhhsuan
        22
    hhhsuan  
       2019-07-26 10:26:48 +08:00
    @wwqgtxx #15 传 fd 本身就是糟糕的设计,即便是线程也要尽量避免。
    wwqgtxx
        23
    wwqgtxx  
       2019-07-26 19:01:15 +08:00 via iPhone
    @hhhsuan 作为一个 web server,跨线程传递一个 socket fd 是非常参见的
    wwqgtxx
        24
    wwqgtxx  
       2019-07-26 19:03:24 +08:00 via iPhone
    @hhhsuan 在保证一个 fd 只会被一个线程操作的情况下,传递 fd 没有任何糟糕的,如果你觉得糟糕,那只能说明你程序写的烂
    hhhsuan
        25
    hhhsuan  
       2019-07-27 09:30:59 +08:00
    @wwqgtxx #24 你说得对,我写的烂
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1205 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 18:05 · PVG 02:05 · LAX 10:05 · JFK 13:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.