最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Swoole中SwooleAtomic::cmpset和set的区别
时间:2026-07-21 09:35:49 编辑:袖梨 来源:一聚教程网
cmpset是条件写、set是无条件覆盖;cmpset仅当当前值等于预期值时才写入新值并返回操作后值,需严格比较返回值;set直接覆盖,无返回值,适合初始化或重置。
cmpset 是条件写,set 是无条件覆盖
SwooleAtomic::cmpset() 不是赋值函数,它只在当前值等于预期值时才写入新值;set() 则不管当前值是什么,直接覆盖。这是根本区别,决定了它们的使用边界。
常见错误是把 cmpset() 当成“带判断的 set”来用,比如想先检查是否为 0 再设为 1,却写成:if ($atomic->get() === 0) { $atomic->set(1); }——这中间存在竞态窗口,两个进程可能同时通过 get() 判断,然后都执行 set(1),导致逻辑失控。
-
cmpset($cmp_value, $new_value)返回的是操作后的当前值(不是布尔值),必须显式比较:if ($atomic->cmpset(0, 1)=== 1) { /* 成功 */ } -
set($value)没有返回值,调用即生效,适合初始化、重置等无需条件判断的场景 - 参数范围一致:两者都要求
$value是 ≤ 4294967295 的非负整数,超限会截断
cmpset 天然用于并发竞争,set 适合单次设定
典型并发场景如「仅允许第一个 Worker 完成配置加载」或「告警开关只触发一次」,必须用 cmpset()。它底层依赖 CPU 的 cmpxchg 指令,整个“比-换”动作不可分割,多个进程同时调用,只有一个能成功。
而 set() 没有竞争语义,适合服务启动时一次性设定初始状态,或定时任务中强制覆盖某个监控指标(如每分钟重置计数器)。
- 若需“首次初始化”,不要用
set()+ 外层 if,而应只调用一次cmpset(0, 1)并检查返回值 - 若需“总是设为某值”,比如清零计数器,
set(0)比反复cmpset($cur, 0)更直接、无失败路径 - 混用时注意:先
set()再cmpset()没问题;但cmpset()失败后直接set()可能掩盖本该拒绝的并发冲突
性能与可见性没有本质差异,但语义误用代价更高
两者底层都走共享内存+CPU 原子指令,单次调用开销接近。但 cmpset() 的失败重试逻辑(如有)会带来实际性能波动,而 set() 是稳定低开销。
真正容易被忽略的是语义层面:很多人以为 cmpset() 返回 true/false,结果写出 if ($atomic->cmpset(0, 1)) { ... } ——这在 PHP 8+ 中可能因返回整数被隐式转为 true 而“看似正常”,但一旦 $new_value 是 0,就永远进不去分支。
- 永远用严格比较:
=== $new_value,不要依赖真假值转换 -
set()不提供任何并发保护能力,它只是原子写,不解决“谁该写”的问题 - 如果业务需要读-改-写复合操作(比如“加 1 但不超过 100”),
cmpset()无法一步完成,得靠循环重试或换用Table+ 行锁
复杂点不在语法,而在你是否清楚自己要解决的是“状态一致性”还是“值覆盖”。用错一个,轻则逻辑重复,重则状态错乱,且难以复现。
相关文章
- 爱剪辑编辑视频方法 07-28
- OA系统快速发送私信技巧 07-28
- 谷歌浏览器如何发送反馈 07-28
- 如何在excel表格里制作柱形动态图表 07-28
- 悟空浏览器怎么分享 07-28
- soundlock 怎样设置开机自启 07-28