类变量和全局变量在多线程环境下的访问有什么区别?
Python 中 类变量 vs 全局变量【多线程访问区别】底层上两者都是共享状态都存在线程不安全问题但是查找路径、修改行为、隔离性有差异。 Python 多线程受 GIL 限制同一时刻只有 1 个线程执行字节码但不是原子操作依然会有竞态。1. 存储位置全局变量存放在模块的__dict__模块字典属于整个模块共享。类变量存放在类对象的__dict__所有实例共享这份类变量实例没有重写赋值时读的时候才去类上找。class A: x 0 # 类变量在A.__dict__ g 0 # 全局变量当前模块 __dict__2. 读取操作多线程读只读场景下全局变量去模块命名空间查找类变量A.x直接访问类字典obj.x先查实例 dict找不到再向上找类 dict✅只读不加写操作两者都安全无竞态只是查找链路略有差别性能微小差距。3. 修改操作核心区别多线程写① 全局变量g 0 def func(): global g g 1g 1不是原子读取 → 计算 → 写回。 多线程并发执行会丢更新竞态条件。 必须global声明否则会当成局部变量。② 类变量class A: x 0 def func(): A.x 1A.x 1同样不是原子操作一样会丢数据线程不安全。⚠️ 坑obj.x xxx不是修改类变量而是给实例新增实例变量不会改动类上的值。a A() a.x 100 # 新建实例属性A.x 不变这是高频踩坑点4. 作用域与隔离差异多线程场景最关键区别全局变量整个模块全部线程共享作用域是模块级别。所有函数、所有线程都能直接读写。一旦污染影响面极大。类变量共享范围仅限这个类和它的实例。不同类之间类变量互不干扰如果你希望多组独立共享状态可以定义多个类天然分组隔离全局变量做分组隔离就很麻烦需要手动维护多个全局变量。5. 锁使用上没有本质差别不管是全局变量还是类变量并发写都需要锁保护from threading import Lock lock Lock() class A: x 0 def thread_func(): for _ in range(10000): with lock: A.x 1全局变量写法也是一样加锁。GIL 不会保护这类复合操作。6. 对比总结表表格维度全局变量类变量共享范围整个模块所有代码、线程同一个类的所有实例、类本身存储位置模块__dict__类对象__dict__并发读安全安全并发写非原子线程不安全非原子线程不安全修改陷阱忘记写 global变成局部变量实例.属性值不会修改类变量新增实例变量状态分组很难容易全局污染方便多个类天然隔离多组共享状态生命周期模块加载创建模块销毁释放类加载创建类被 GC 回收销毁7. 实践建议多线程共享状态优先类变量封装把共享变量 锁 操作方法封装到类内代码更清晰、隔离好。mp.scel.cn/blog/9kLm2QpX7a.htmlmp.scel.cn/blog/Zx4Tn8Vr1B.htmlmp.scel.cn/blog/Qw7Yh3Ns5D.htmlmp.scel.cn/blog/Mc2Jv9Kp6E.htmlmp.scel.cn/blog/Rt8Bn4Xz0F.htmlmp.scel.cn/blog/Hg5Lp1Wq7G.htmlmp.scel.cn/blog/Uv3Dm6Yr2H.htmlmp.scel.cn/blog/Pa9Kc4Nt8J.htmlmp.scel.cn/blog/Se2Qx7Vb5K.htmlmp.scel.cn/blog/Fn6Wm1Zp3L.htmlmp.scel.cn/blog/Yd4Hr9Cv2M.htmlmp.scel.cn/blog/Jk7Tq3Bs8N.htmlmp.scel.cn/blog/Ol1Pm5Xw6P.htmlmp.scel.cn/blog/Bg8Nc2Vr4Q.htmlmp.scel.cn/blog/Xm5Kt7Yd1R.htmlmp.scel.cn/blog/Cv9Qp3Ln6S.htmlmp.scel.cn/blog/Zr2Wm8Hx4T.htmlmp.scel.cn/blog/Nk6Jd1Vp9U.htmlmp.scel.cn/blog/Lq4Yt7Bc2V.htmlmp.scel.cn/blog/Wp8Rm3Nx5W.htmlmp.scel.cn/blog/Td1Kv6Qs9X.htmlmp.scel.cn/blog/Hx5Pm2Zr7Y.htmlmp.scel.cn/blog/Gc9Bn4Wt1Z.htmlmp.scel.cn/blog/Vr3Lq8Jd6A.htmlmp.scel.cn/blog/Mp7Yx2Kc5B.htmlmp.scel.cn/blog/Ks4Wm9Nv3C.htmlmp.scel.cn/blog/Qn1Rt6Bp8D.htmlmp.scel.cn/blog/Dz5Jv2Xm7E.htmlmp.scel.cn/blog/Sb9Lq4Hr1F.htmlmp.scel.cn/blog/Yt3Pm8Kx6G.htmlmp.scel.cn/blog/Rc7Wn1Vd4H.htmlmp.scel.cn/blog/Bp2Qx9Lm5J.htmlmp.scel.cn/blog/Nv6Tr3Yc8K.htmlmp.scel.cn/blog/Lm1Jd7Wp2L.htmlmp.scel.cn/blog/Xq5Kv9Bn4M.htmlmp.scel.cn/blog/Ct8Rm2Hx7N.htmlmp.scel.cn/blog/Zp3Yq6Ld1P.htmlmp.scel.cn/blog/Gv9Wm4Nc5Q.htmlmp.scel.cn/blog/Hk2Jx7Rt8R.htmlmp.scel.cn/blog/Md6Pq1Bv3S.htmlmp.scel.cn/blog/Tn8Lm5Wx2T.htmlmp.scel.cn/blog/Qr4Yp9Kc7U.htmlmp.scel.cn/blog/Vx1Jv6Nd3V.htmlmp.scel.cn/blog/Kp7Wm2Ht9W.htmlmp.scel.cn/blog/Bc5Rq8Lx4X.htmlmp.scel.cn/blog/Nm9Yd3Pv1Y.htmlmp.scel.cn/blog/Lt2Kx7Bc6Z.htmlmp.scel.cn/blog/Xv8Qm4Nr5A.htmlmp.scel.cn/blog/Cp1Jd9Wt3B.htmlmp.scel.cn/blog/Zk6Lq2Yx8C.htmlmp.scel.cn/blog/Gr3Pm7Vc1D.htmlmp.scel.cn/blog/Hx9Bn5Kd4E.htmlmp.scel.cn/blog/Mv2Tq8Lm6F.htmlmp.scel.cn/blog/Tc7Yp1Rx3G.htmlmp.scel.cn/blog/Qm4Jv9Wd5H.htmlmp.scel.cn/blog/Vp8Km2Nx7J.htmlmp.scel.cn/blog/Kd1Lq6Bt9K.htmlmp.scel.cn/blog/Bx5Rm3Yc2L.htmlmp.scel.cn/blog/Nq9Pv7Hd4M.htmlmp.scel.cn/blog/Lm3Jx1Wt6N.htmlmp.scel.cn/blog/Xc8Qm5Bv2P.htmlmp.scel.cn/blog/Cv4Kd9Nr7Q.htmlmp.scel.cn/blog/Zp1Yq6Lx3R.htmlmp.scel.cn/blog/Gt7Wm2Vc9S.htmlmp.scel.cn/blog/Hk5Jv8Rd1T.htmlmp.scel.cn/blog/Mx9Pq3Bn6U.htmlmp.scel.cn/blog/Tm2Ld7Wv4V.htmlmp.scel.cn/blog/Qc6Yp1Kx8W.htmlmp.scel.cn/blog/Vr3Jm9Nt5X.htmlmp.scel.cn/blog/Kp8Qv4Bd2Y.htmlmp.scel.cn/blog/Bm1Lx6Wc7Z.htmlmp.scel.cn/blog/Nv5Rd9Yp3A.htmlmp.scel.cn/blog/Lq2Km7Jx8B.htmlmp.scel.cn/blog/Xt9Pm4Vc1C.htmlmp.scel.cn/blog/Cd3Qv8Bn6D.htmlmp.scel.cn/blog/Zx7Lp2Yr5E.htmlmp.scel.cn/blog/Gm1Jd6Wv9F.htmlmp.scel.cn/blog/Hv4Kq9Nx2G.htmlmp.scel.cn/blog/Mp8Rm3Bc7H.htmlmp.scel.cn/blog/Tq1Yv5Ld4J.htmlmp.scel.cn/blog/Qx6Jm2Wt9K.htmlmp.scel.cn/blog/Vc3Pq7Rn1L.htmlmp.scel.cn/blog/Km9Ld4Bv6M.htmlmp.scel.cn/blog/Bp2Xv8Yc3N.htmlmp.scel.cn/blog/Nr5Qm1Jx7P.htmlmp.scel.cn/blog/Lv8Kd3Wt2Q.htmlmp.scel.cn/blog/Xm4Pq9Bc6R.htmlmp.scel.cn/blog/Ct1Rv7Lx5S.htmlmp.scel.cn/blog/Zp8Jm2Yd4T.htmlmp.scel.cn/blog/Gq3Kv6Nx9U.htmlmp.scel.cn/blog/Hm7Ld1Wc5V.htmlmp.scel.cn/blog/Mv4Pq8Bt2W.htmlmp.scel.cn/blog/Tr9Ym3Jx6X.htmlmp.scel.cn/blog/Qc2Kv7Ld1Y.htmlmp.scel.cn/blog/Vp6Rm4Nc8Z.htmlmp.scel.cn/blog/Kx1Jd9Wv3A.htmlmp.scel.cn/blog/Bm5Qq2Yt7B.htmlmp.scel.cn/blog/Nc8Lm4Hx1C.htmlmp.scel.cn/blog/Lv3Pq9Rd6D.htmlmp.scel.cn/blog/Xt7Km2Bc5E.html尽量少用全局变量全局状态容易被任意函数意外修改调试困难。无论用哪一种只要存在并发写都必须加锁。如果你想我可以写一段完整可运行代码演示类变量多线程丢值和全局变量多线程丢值的对比。