Google 了一下 "Python" "CAS",只是搜到了一些关于 GIL 的 ATOMIC 操作。
但是觉得 Python 的 Lock() 又有点沉,有大佬知道有没有类似 CAS 的轻量级实现吗?
|      1dqzcwxb      2021-10-18 12:12:15 +08:00 等一个莫名其妙喷 java 的 不过也有可能没有,因为 cas 不多学点 java 还真不知道是什么 | 
|      2Goat121      2021-10-18 12:24:18 +08:00 @dqzcwxb java 被喷不是语言的问题,正是因为你这种 java boy 太多,让我等羞于为伍,说自己写过几年 java 都心惊胆战怕被人误认为你们。 cas 和 java 又有什么关系了?人家实现 cas 的时候还没现代操作系统呢,你家 jvm 都没地方跑谢谢。 | 
|      3dqzcwxb      2021-10-18 13:14:38 +08:00 @Goat121 #2 "等一个莫名其妙喷 java 的"你可真会咬钩 我没说 cas 跟 java 有关系,只是某些喷 java 的喜欢带上 同理设计模式也跟 java 没啥关系,还不是天天喷 java 设计模式滥用? 还羞与为伍,笑死 | 
|  |      4BBCCBB      2021-10-18 13:22:17 +08:00 没发现有, python 单进程的, 直接用 Lock(). | 
|  |      6est      2021-10-18 13:36:31 +08:00 没有而且不需要。因为 GIL 直接保证了同步。 | 
|      8dqzcwxb      2021-10-18 14:13:44 +08:00 @janxin #5 设计模式不是 java 独有的,也不是 java 发明 cas 不是 java 独有的,也不是 java 发明 | 
|      9securityCoding      2021-10-18 14:16:04 +08:00 设计模式跟语言无关 , 基本上有点名气的开源项目里面都是设计模式的影子在里面 | 
|      10greenmoon55      2021-10-18 14:25:12 +08:00 | 
|  |      11stach      2021-10-18 15:06:10 +08:00 Python 一般我都用 Lock() 来确保类似 i += 1 这种操作的原子性, 之前查找资料有实现原子性的一些库, 不过没用过. | 
|  |      12ipwx      2021-10-18 15:17:19 +08:00 Python 的 CAS 将是一场灾难啊。。。GIL 把一个忙等待的线程切了进来。。。 | 
|  |      14sujin190      2021-10-18 15:35:31 +08:00 CAS 是 cpu 指令级提供的冲突处理的,python 一个+1 操作都好多条 cpu 指令了,这个在 python 层面上来看已经毫无意义了吧 | 
|  |      15abersheeran      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 还扣这个锁的性能吧?大可不必啊 | 
|  |      16abersheeran      2021-10-18 15:43:20 +08:00 @sujin190 在 CPython 虚拟机里,是按照字节码来逐个执行的。对于一个单进程 CPython 程序来说,字节码层面的原子性就足够了,CPU 级别的才是没有意义。 | 
|  |      18sujin190      2021-10-18 15:52:35 +08:00  1 @abersheeran #16 但这个实现没啥现实意义啊,CPU 级 CAS 的价值是在多核中,CAS 可以通过占用少量 CPU 时间来换取通过更重度的锁来导致线程休眠切换调度的问题,同时还可以最大限度保护内核缓存失效的问题,毕竟现代 cpu 和缓存速度太快了,但是你在 Python 层面做一个这东西似乎啥都没解决吧,没啥意义确实没啥提供的必要 | 
|  |      19abersheeran      2021-10-18 15:55:29 +08:00 @sujin190 为了 CAS 而上 CAS 的人还是挺多的,毕竟是吹嘘的资本,尽管在他们手里几乎解决不了任何实际问题。 | 
|  |      20sujin190      2021-10-18 15:55:36 +08:00 @est #17 最简单一条赋值语句一般有三条 bytecode 组成,单条 bytecode 是线程安全的,多条之间不是,你可以用 dis 显示下编译出的 bytecode 就知道了 | 
|  |      21sujin190      2021-10-18 15:59:39 +08:00 @abersheeran #19 确实了,Python 上 CAS 确实是为了 CAS 而 CAS 了,毕竟 GIL 限制了,不过如果你搞个扩展释放掉 GIL 的话就可以搞了 | 
|      22sampeng      2021-10-18 16:15:38 +08:00 看完讨论。。我以为是 CAS 单点登录,我还纳闷这有啥好讨论的。。。落伍了落伍了 | 
|  |      23fgwmlhdkkkw      2021-10-18 16:17:27 +08:00 搜 atomic 好像有几个,试试看? | 
|  |      24woctordho      2021-10-18 17:03:12 +08:00  1 我还以为是 computer algebra system,差点开始安利 SageMath ( | 
|  |      25abersheeran      2021-10-18 17:09:17 +08:00 @sujin190 搞扩展那也是别的语言了,一般是 C,C 的 CAS 这资料还不到处都是,可以说跟 Python 一点关系都没有了。哈哈哈。 | 
|      26junkun      2021-10-18 19:57:03 +08:00 @sujin190 https://docs.python.org/3.10/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe,但是这里面说 x=y,和 x.field=y 是 atomic 的。(内置类型限定) | 
|      27yunluw      2021-10-18 20:57:02 +08:00  1 此贴前三楼以自己为示范展示了不加控制的人类本性 | 
|  |      28dingwen07      2021-10-18 21:50:29 +08:00 via iPhone 点击来之前以为是计算机代数系统 | 
|      302i2Re2PLMaDnghL      2021-10-18 22:39:46 +08:00 @securityCoding 设计模式的影子就不叫设计模式。设计模式的全部想法都是在(拙劣、错误且反思考地)尝试提取习惯性操作并为之取个名字。 你这就好比大多数语言给 a=1 取个名字叫「赋值」,然后说『( Haskell 的) let a=1 in ... 有赋值的影子』,这说明你被词汇和词义限制住了思想。 | 
|      31Hstar      2021-10-18 22:51:20 +08:00 据我所知,Python 只有.append() 是 aotmic 的,有点小坑但是有 GIL 了 | 
|  |      32imycc      2021-10-18 23:01:31 +08:00 恕我孤陋寡闻,python 确保线程安全的一般手段应该就是 threading.Lock,还真没见过其他方式 | 
|      33Jooooooooo      2021-10-18 23:11:25 +08:00 @dqzcwxb 有毒. 楼主完全没提 java 你 1L 莫名其妙来个喷 Java? | 
|      34future0906      2021-10-19 00:19:58 +08:00 @Trim21 不是,你就好好学学啥是 GIL 。threading.Lock 主要是保证 PythonVM 外的临界区的。 | 
|  |      35Trim21      2021-10-19 00:33:37 +08:00 你可以直接说你想表达的东西 | 
|  |      36Trim21      2021-10-19 00:33:49 +08:00 @future0906 #34 你可以直接说你想表达的东西 | 
|  |      37msaionyc      2021-10-19 08:30:33 +08:00 via iPhone  1 1 楼这种真的是毒瘤,立个靶子自己打,败坏社区氛围,引战 | 
|  |      38dingyaguang117      2021-10-19 09:25:33 +08:00 via iPhone @future0906 真的吗?有了 GIL 什么都不用考虑了? | 
|  |      39monetto OP @dingyaguang117 Python2 中 GIL 是运行 1000 行字节码,然后切换线程,Python3 是 15 毫秒切换线程。GIL 跟线程安全根本毫无关系,除非你能精准的控制字节码的数量。其次就是,dict.append,list.pop 这种 C 语言调用实现,是 Atomic 的。 | 
|  |      41sujin190      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 的内存结构来说,其实就算被拆开其实越不会有副作用,所以认为是原子操作其实也没有啥问题 | 
|  |      42sujin190      2021-10-19 14:02:42 +08:00 @monetto #39 Python 的 GIL 就是用来保证内部数据结构线程安全的,否则直接删掉 GIL 就是了啊,所以肯定必须要求是单条字节码完整执行完成才能切换,不可能像操作系统线程一样时间一到啥都不管就直接切换吧,否则 Python 内部自身的数据结构都有可能被破坏了,从这一点上来说,GIL 保证单条字节码的完整性,确实提供了大量线程安全的操作,比如赋值,不能说毫无关系吧 | 
|  |      43monetto OP @sujin190 嗯嗯,毫无关系确实不至于,对象内部的线程安全确实没错,不过问题是只有 CPython 存在 GIL,JPython 是没有的。 | 
|  |      44dingyaguang117      2021-10-20 08:57:52 +08:00 via iPhone @sujin190 GIL 是用来保证对象内部线程安全怎么理解,什么是内部对象,那些场景线程安全? | 
|  |      45dingyaguang117      2021-10-20 09:11:40 +08:00 via iPhone @sujin190 应该是只有单字节码的操作才能保证线程安全。a=a+1 应该都不是 | 
|  |      46dingyaguang117      2021-10-20 09:13:50 +08:00 via iPhone @monetto GIL 锁不能完全解决线程安全问题,举个例子:一个线程遍历 dict,另一个删除。线程安全问题不仅是一行语句的安全 | 
|  |      47monetto OP @dingyaguang117 晕...我上面不是说了吗...保证对象的 pop,append 线程安全,内部的,不是两个线程同时操作。我没说两个线程同时操作线程安全。因为 pop 和 append 是 C 语言调用,C 语言调用的都是 ATOMIC 的。 | 
|  |      48monetto OP @dingyaguang117 人家说的是内部数据结构,是 pop,remove 等内部的操作,不是让你两个线程同时操作的...理解错了吧兄弟 | 
|  |      49sujin190      2021-10-20 12:18:15 +08:00 via Android @dingyaguang117 Python 解释器也需要用内存,也有数据结构啊,编译,创建类,模块导入,线程创建,文件操作,套接字这些底层也是用 GIL 保证线程安全的吧 | 
|  |      50sujin190      2021-10-20 12:27:06 +08:00 via Android @dingyaguang117 其实 dict 迭代器生成,删除其实就一天字节码指令,线程安全的逻辑并没有改变,a=a+1 应该是三条指令,加载、计算和保存,事实上除了计算,前两条指令不会有副作用,加法因为内存结构是指针操作,这么看其实这个其实也没有并发安全问题,但是大多数情况下这个操作需要加锁,估计是后面大概率就是判断语句,而这两之间就不是线程安全的了吧 | 
|  |      51sujin190      2021-10-20 12:46:34 +08:00 via Android @dingyaguang117 好吧,纠正一下,数字加法指令会返回新的数字对象,所以保存这个字节码在多线程下这种情况就不是线程安全的了 |