Python 中 有 CAS 的实现吗 - V2EX
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
monetto
V2EX    Python

Python 中 有 CAS 的实现吗

  •  
  •   monetto 2021-10-18 11:33:15 +08:00 6140 次点击
    这是一个创建于 1501 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Google 了一下 "Python" "CAS",只是搜到了一些关于 GIL 的 ATOMIC 操作。

    但是觉得 Python 的 Lock() 又有点沉,有大佬知道有没有类似 CAS 的轻量级实现吗?

    第 1 条附言    2021-10-19 10:36:34 +08:00
    统一回复了,我是使用一个标记变量 + 短代码实现类似 CAS 的效果,在 for _ in range(1000000):加法中四个线程大概用时 5 秒,并保证了总数是 4000000 。
    而直接使用 Lock 耗时是 17 秒。

    GIL 在 Python2 中是 1000 行字节码切换线程,Python3 中是 15 毫秒切换线程。list.pop 这种 C 调用是 atomic 的。
    51 条回复    2021-10-20 12:46:34 +08:00
    dqzcwxb
        1
    dqzcwxb  
       2021-10-18 12:12:15 +08:00
    等一个莫名其妙喷 java 的
    不过也有可能没有,因为 cas 不多学点 java 还真不知道是什么
    Goat121
        2
    Goat121  
       2021-10-18 12:24:18 +08:00
    @dqzcwxb java 被喷不是语言的问题,正是因为你这种 java boy 太多,让我等羞于为伍,说自己写过几年 java 都心惊胆战怕被人误认为你们。
    cas 和 java 又有什么关系了?人家实现 cas 的时候还没现代操作系统呢,你家 jvm 都没地方跑谢谢。
    dqzcwxb
        3
    dqzcwxb  
       2021-10-18 13:14:38 +08:00
    @Goat121 #2 "等一个莫名其妙喷 java 的"你可真会咬钩
    我没说 cas 跟 java 有关系,只是某些喷 java 的喜欢带上
    同理设计模式也跟 java 没啥关系,还不是天天喷 java 设计模式滥用?
    还羞与为伍,笑死
    BBCCBB
        4
    BBCCBB  
       2021-10-18 13:22:17 +08:00
    没发现有, python 单进程的, 直接用 Lock().
    janxin
        5
    janxin  
       2021-10-18 13:23:48 +08:00
    @dqzcwxb ???为什么喷 Java 要带上 CAS 啊,你说设计模式我还能理解
    est
        6
    est  
       2021-10-18 13:36:31 +08:00
    没有而且不需要。因为 GIL 直接保证了同步。
    monetto
        7
    monetto  
    OP
       2021-10-18 13:41:12 +08:00
    @est GIL 不等于线程安全,GIL 不保证线程变量同步。
    dqzcwxb
        8
    dqzcwxb  
       2021-10-18 14:13:44 +08:00
    @janxin #5 设计模式不是 java 独有的,也不是 java 发明
    cas 不是 java 独有的,也不是 java 发明
    securityCoding
        9
    securityCoding  
       2021-10-18 14:16:04 +08:00
    设计模式跟语言无关 , 基本上有点名气的开源项目里面都是设计模式的影子在里面
    stach
        11
    stach  
       2021-10-18 15:06:10 +08:00
    Python 一般我都用 Lock() 来确保类似 i += 1 这种操作的原子性, 之前查找资料有实现原子性的一些库, 不过没用过.
    ipwx
        12
    ipwx  
       2021-10-18 15:17:19 +08:00
    Python 的 CAS 将是一场灾难啊。。。GIL 把一个忙等待的线程切了进来。。。
    Trim21
        13
    Trim21  
       2021-10-18 15:18:24 +08:00
    @est #6 保证不了,不说 if 和赋值之间会不会切线程,就是赋值也不一定安全
    sujin190
        14
    sujin190  
       2021-10-18 15:35:31 +08:00
    CAS 是 cpu 指令级提供的冲突处理的,python 一个+1 操作都好多条 cpu 指令了,这个在 python 层面上来看已经毫无意义了吧
    abersheeran
        15
    abersheeran  
       2021-10-18 15:41:31 +08:00   1
    比较难想象 Python 怎么 CAS,l.a = b 不是原子的,这要变成三条字节码,两个 LOAD_NAME 和一个 STORE_NAME 。
    如果直接用 a = b,那你压根拿不到 a 的结果,因为 Python 没有指针,函数里赋值过去就没了。
    如果用 nonlocal global 去修复拿结果的问题,那就没办法做到无副作用,而且这只是换了个 name,对象所在的内存还是没有变化。

    综上所述,建议直接 threading.Lock,不会有人上了 Python 还扣这个锁的性能吧?大可不必啊
    abersheeran
        16
    abersheeran  
       2021-10-18 15:43:20 +08:00
    @sujin190 在 CPython 虚拟机里,是按照字节码来逐个执行的。对于一个单进程 CPython 程序来说,字节码层面的原子性就足够了,CPU 级别的才是没有意义。
    est
        17
    est  
       2021-10-18 15:48:59 +08:00
    @Trim21 赋值都不安全?看来我孤陋寡闻了。233
    sujin190
        18
    sujin190  
       2021-10-18 15:52:35 +08:00   1
    @abersheeran #16 但这个实现没啥现实意义啊,CPU 级 CAS 的价值是在多核中,CAS 可以通过占用少量 CPU 时间来换取通过更重度的锁来导致线程休眠切换调度的问题,同时还可以最大限度保护内核缓存失效的问题,毕竟现代 cpu 和缓存速度太快了,但是你在 Python 层面做一个这东西似乎啥都没解决吧,没啥意义确实没啥提供的必要
    abersheeran
        19
    abersheeran  
       2021-10-18 15:55:29 +08:00
    @sujin190 为了 CAS 而上 CAS 的人还是挺多的,毕竟是吹嘘的资本,尽管在他们手里几乎解决不了任何实际问题。
    sujin190
        20
    sujin190  
       2021-10-18 15:55:36 +08:00
    @est #17 最简单一条赋值语句一般有三条 bytecode 组成,单条 bytecode 是线程安全的,多条之间不是,你可以用 dis 显示下编译出的 bytecode 就知道了
    sujin190
        21
    sujin190  
       2021-10-18 15:59:39 +08:00
    @abersheeran #19 确实了,Python 上 CAS 确实是为了 CAS 而 CAS 了,毕竟 GIL 限制了,不过如果你搞个扩展释放掉 GIL 的话就可以搞了
    sampeng
        22
    sampeng  
       2021-10-18 16:15:38 +08:00
    看完讨论。。我以为是 CAS 单点登录,我还纳闷这有啥好讨论的。。。落伍了落伍了
    fgwmlhdkkkw
        23
    fgwmlhdkkkw  
       2021-10-18 16:17:27 +08:00
    搜 atomic 好像有几个,试试看?
    woctordho
        24
    woctordho  
       2021-10-18 17:03:12 +08:00   1
    我还以为是 computer algebra system,差点开始安利 SageMath (
    abersheeran
        25
    abersheeran  
       2021-10-18 17:09:17 +08:00
    @sujin190 搞扩展那也是别的语言了,一般是 C,C 的 CAS 这资料还不到处都是,可以说跟 Python 一点关系都没有了。哈哈哈。
    junkun
        26
    junkun  
       2021-10-18 19:57:03 +08:00
    yunluw
        27
    yunluw  
       2021-10-18 20:57:02 +08:00   1
    此贴前三楼以自己为示范展示了不加控制的人类本性
    dingwen07
        28
    dingwen07  
       2021-10-18 21:50:29 +08:00 via iPhone
    点击来之前以为是计算机代数系统
    guoli100
        29
    guoli100  
       2021-10-18 22:36:11 +08:00
    @dingwen07 我第一眼也以为是说计算机代数系统
    2i2Re2PLMaDnghL
        30
    2i2Re2PLMaDnghL  
       2021-10-18 22:39:46 +08:00
    @securityCoding 设计模式的影子就不叫设计模式。设计模式的全部想法都是在(拙劣、错误且反思考地)尝试提取习惯性操作并为之取个名字。
    你这就好比大多数语言给 a=1 取个名字叫「赋值」,然后说『( Haskell 的) let a=1 in ... 有赋值的影子』,这说明你被词汇和词义限制住了思想。
    Hstar
        31
    Hstar  
       2021-10-18 22:51:20 +08:00
    据我所知,Python 只有.append() 是 aotmic 的,有点小坑但是有 GIL 了
    imycc
        32
    imycc  
       2021-10-18 23:01:31 +08:00
    恕我孤陋寡闻,python 确保线程安全的一般手段应该就是 threading.Lock,还真没见过其他方式
    Jooooooooo
        33
    Jooooooooo  
       2021-10-18 23:11:25 +08:00
    @dqzcwxb 有毒. 楼主完全没提 java 你 1L 莫名其妙来个喷 Java?
    future0906
        34
    future0906  
       2021-10-19 00:19:58 +08:00
    @Trim21 不是,你就好好学学啥是 GIL 。threading.Lock 主要是保证 PythonVM 外的临界区的。
    Trim21
        35
    Trim21  
       2021-10-19 00:33:37 +08:00
    你可以直接说你想表达的东西
    Trim21
        36
    Trim21  
       2021-10-19 00:33:49 +08:00
    @future0906 #34 你可以直接说你想表达的东西
    msaionyc
        37
    msaionyc  
       2021-10-19 08:30:33 +08:00 via iPhone   1
    1 楼这种真的是毒瘤,立个靶子自己打,败坏社区氛围,引战
    dingyaguang117
        38
    dingyaguang117  
       2021-10-19 09:25:33 +08:00 via iPhone
    @future0906 真的吗?有了 GIL 什么都不用考虑了?
    monetto
        39
    monetto  
    OP
       2021-10-19 10:30:31 +08:00
    @dingyaguang117 Python2 中 GIL 是运行 1000 行字节码,然后切换线程,Python3 是 15 毫秒切换线程。GIL 跟线程安全根本毫无关系,除非你能精准的控制字节码的数量。其次就是,dict.append,list.pop 这种 C 语言调用实现,是 Atomic 的。
    monetto
        40
    monetto  
    OP
       2021-10-19 10:35:18 +08:00
    @monetto dict 没有 append,说错了,remove
    sujin190
        41
    sujin190  
       2021-10-19 13:58:08 +08:00
    def f():
    ...: a=1
    ...: b=a


    2 0 LOAD_CONST 1 (1)
    2 STORE_FAST 0 (a)

    3 4 LOAD_FAST 0 (a)
    6 STORE_FAST 1 (b)
    8 LOAD_CONST 0 (None)

    @junkun #26 一个赋值语句两条字节码组成,以 Python 的内存结构来说,其实就算被拆开其实越不会有副作用,所以认为是原子操作其实也没有啥问题
    sujin190
        42
    sujin190  
       2021-10-19 14:02:42 +08:00
    @monetto #39 Python 的 GIL 就是用来保证内部数据结构线程安全的,否则直接删掉 GIL 就是了啊,所以肯定必须要求是单条字节码完整执行完成才能切换,不可能像操作系统线程一样时间一到啥都不管就直接切换吧,否则 Python 内部自身的数据结构都有可能被破坏了,从这一点上来说,GIL 保证单条字节码的完整性,确实提供了大量线程安全的操作,比如赋值,不能说毫无关系吧
    monetto
        43
    monetto  
    OP
       2021-10-19 14:29:50 +08:00
    @sujin190 嗯嗯,毫无关系确实不至于,对象内部的线程安全确实没错,不过问题是只有 CPython 存在 GIL,JPython 是没有的。
    dingyaguang117
        44
    dingyaguang117  
       2021-10-20 08:57:52 +08:00 via iPhone
    @sujin190 GIL 是用来保证对象内部线程安全怎么理解,什么是内部对象,那些场景线程安全?
    dingyaguang117
        45
    dingyaguang117  
       2021-10-20 09:11:40 +08:00 via iPhone
    @sujin190 应该是只有单字节码的操作才能保证线程安全。a=a+1 应该都不是
    dingyaguang117
        46
    dingyaguang117  
       2021-10-20 09:13:50 +08:00 via iPhone
    @monetto GIL 锁不能完全解决线程安全问题,举个例子:一个线程遍历 dict,另一个删除。线程安全问题不仅是一行语句的安全
    monetto
        47
    monetto  
    OP
       2021-10-20 10:24:14 +08:00
    @dingyaguang117 晕...我上面不是说了吗...保证对象的 pop,append 线程安全,内部的,不是两个线程同时操作。我没说两个线程同时操作线程安全。因为 pop 和 append 是 C 语言调用,C 语言调用的都是 ATOMIC 的。
    monetto
        48
    monetto  
    OP
       2021-10-20 10:25:15 +08:00
    @dingyaguang117 人家说的是内部数据结构,是 pop,remove 等内部的操作,不是让你两个线程同时操作的...理解错了吧兄弟
    sujin190
        49
    sujin190  
       2021-10-20 12:18:15 +08:00 via Android
    @dingyaguang117 Python 解释器也需要用内存,也有数据结构啊,编译,创建类,模块导入,线程创建,文件操作,套接字这些底层也是用 GIL 保证线程安全的吧
    sujin190
        50
    sujin190  
       2021-10-20 12:27:06 +08:00 via Android
    @dingyaguang117 其实 dict 迭代器生成,删除其实就一天字节码指令,线程安全的逻辑并没有改变,a=a+1 应该是三条指令,加载、计算和保存,事实上除了计算,前两条指令不会有副作用,加法因为内存结构是指针操作,这么看其实这个其实也没有并发安全问题,但是大多数情况下这个操作需要加锁,估计是后面大概率就是判断语句,而这两之间就不是线程安全的了吧
    sujin190
        51
    sujin190  
       2021-10-20 12:46:34 +08:00 via Android
    @dingyaguang117 好吧,纠正一下,数字加法指令会返回新的数字对象,所以保存这个字节码在多线程下这种情况就不是线程安全的了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1232 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 17:19 PVG 01:19 LAX 09:19 JFK 12:19
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86