news 2026/10/15 16:02:58

幂等性学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
幂等性学习笔记

📘 WPF 幂等性学习笔记

核心一句话:同一个操作,执行一次和执行 N 次,对系统产生的最终影响必须完全一样。


一、概念篇

1.1 定义

幂等(Idempotent)源自数学:f(f(x)) = f(x),即函数重复作用于自身结果不变。

在软件工程中:同一操作被执行一次与被执行多次,系统的最终状态完全相同。

1.2 两个视角

视角说明
数学f(f(x)) = f(x),重复应用结果不变
HTTPGET/PUT/DELETE天然幂等;POST不幂等(重复提交会创建多份资源)

1.3 生活类比

例子是否幂等原因
电梯"关门"按钮✅按 1 次和按 10 次,门只关一次
手机音量设为 50%✅设多少次都是 50%(Set 语义)
遥控器"开/关"键❌按两次灯又灭了(Toggle 语义)
银行转账扣款 100 元❌重复执行会扣多次,必须靠机制保证

1.4 天然幂等 vs 非幂等操作

操作类型示例是否幂等
查询 ReadSELECT/ 读取属性✅
删除 Delete删除id=5的记录(再删结果一样)✅
整体赋值 Setx = 5/UPDATE name='a'✅
自增 Incrementx = x + 1❌
追加 Append日志追加 /List.Add❌
创建 CreateINSERT新订单❌(需幂等键保护)

1.5 WPF 客户端为什么需要幂等

  • 用户手抖双击按钮→ 重复提交订单
  • 网络超时重试→ 重复下单
  • 事件被多次订阅→ 处理器执行 N 次
  • 窗口被重复打开→ 出现多个实例
  • 定时器 / 异步回调重入→ 状态错乱
  • 多端并发保存→ 数据互相覆盖

二、WPF 经典示例篇

示例 1:按钮防重复提交(最经典)⭐

场景:点击"提交订单",请求耗时 2 秒,用户等不及连点 5 下 → 生成 5 笔订单。

// ❌ 非幂等:双击 = 提交两次privateasyncvoidSubmit_Click(objectsender,RoutedEventArgse){await_orderService.CreateOrderAsync();}
// ✅ 幂等:状态守卫 + 按钮禁用,重复点击只生效一次privatebool_isSubmitting;privateasyncvoidSubmit_Click(objectsender,RoutedEventArgse){if(_isSubmitting)return;// 幂等守卫:进行中直接忽略_isSubmitting=true;BtnSubmit.IsEnabled=false;// UI 层再兜底一层try{await_orderService.CreateOrderAsync();}finally{_isSubmitting=false;BtnSubmit.IsEnabled=true;}}

流程图:

是

否

用户点击提交按钮

isSubmitting 为 true?

忽略本次点击

置标志为 true 并禁用按钮

发送创建订单请求

请求完成

恢复按钮并复位标志

要点:finally保证异常时也能复位;逻辑守卫是主防线,禁用按钮只是 UI 兜底。


示例 2:ICommand.CanExecute —— 框架级幂等防线

场景:MVVM 模式下,WPF 命令系统在CanExecute返回false时自动禁用按钮,命令根本不会被触发。

publicclassAsyncRelayCommand:ICommand{privatebool_isExecuting;publicboolCanExecute(objectparameter)=>!_isExecuting;// 执行中 → 按钮自动禁用 → 重复触发无效publicasyncvoidExecute(objectparameter){_isExecuting=true;RaiseCanExecuteChanged();// 通知 UI 刷新按钮状态try{awaitExecuteAsync();}finally{_isExecuting=false;RaiseCanExecuteChanged();}}}

要点:把幂等守卫封装进 Command 基类,所有 ViewModel 复用,一劳永逸。


示例 3:窗口单例 —— 防止重复打开窗口

场景:连点"打开设置"按钮,弹出 5 个设置窗口。

// ❌ 非幂等:点几次开几个privatevoidOpenSettings_Click(objectsender,RoutedEventArgse)=>newSettingsWindow().Show();
// ✅ 幂等:无论点多少次,永远只有一个设置窗口privatevoidOpenSettings_Click(objectsender,RoutedEventArgse){varexisting=Application.Current.Windows.OfType<SettingsWindow>().FirstOrDefault();if(existing!=null){existing.Activate();// 已存在 → 激活置顶即可return;}newSettingsWindow().Show();}

要点:Show()换成ShowDialog()时更要注意,模态窗口重复打开会锁死 UI 线程。


示例 4:事件订阅"先减后加" ⭐

场景:页面每次加载都+=一次,返回再进入后事件触发时处理器执行 2 次、3 次……还会导致内存泄漏。

// ❌ 非幂等:重复订阅protectedoverridevoidOnLoaded(RoutedEventArgse){_service.DataChanged+=OnDataChanged;// 每次加载都叠加一份}
// ✅ 幂等:先减后加,订阅多少次都只注册一份protectedoverridevoidOnLoaded(RoutedEventArgse){_service.DataChanged-=OnDataChanged;// 先解除_service.DataChanged+=OnDataChanged;// 再订阅}

要点:CommunityToolkit.Mvvm的Messenger同理 —— 先Unregister再Register。


示例 5:属性 Setter —— 值不变则跳过

场景:给Title赋相同值,PropertyChanged被反复触发,绑定 UI 无效刷新。

// ✅ 幂等:值没变就不做任何事privatestring_title;publicstringTitle{get=>_title;set{if(_title==value)return;// 幂等守卫_title=value;OnPropertyChanged(nameof(Title));}}

要点:CommunityToolkit.Mvvm生成的SetProperty已内置此判断 —— 这就是幂等思想的框架化。


示例 6:初始化只执行一次

场景:多个页面都调用"确保数据库已初始化",初始化逻辑被跑多次。

// ✅ Lazy<Task<T>>:无论调用多少次,初始化只真正执行一次privatestaticreadonlyLazy<Task<DatabaseService>>_instance=new(()=>DatabaseService.InitAsync());publicstaticTask<DatabaseService>GetServiceAsync()=>_instance.Value;

要点:Lazy<T>默认线程安全;缓存的是Task而不是结果,避免并发时重复初始化。


示例 7:集合刷新 —— 整体覆盖代替增量追加

场景:点"刷新"按钮重新拉取列表,若用Add追加,数据越刷越多。

// ✅ 幂等:Clear + Add = Set 语义,刷新 100 次结果一致publicasyncTaskRefreshAsync(){vardata=await_api.GetItemsAsync();Items.Clear();foreach(varitemindata)Items.Add(item);}

要点:刷新类操作一律用"覆盖"语义;数据量大时可整体替换集合引用以减少 UI 闪烁。


示例 8:定时器 / 异步回调重入保护

场景:DispatcherTimer每 1 秒触发一次,但工作耗时 3 秒 → 多个工作同时跑,状态错乱。

privateint_isRunning;privateasyncvoidOnTimerTick(objectsender,EventArgse){// 原子操作:0 换 1 成功才继续,防止重入if(Interlocked.CompareExchange(ref_isRunning,1,0)!=0)return;try{awaitDoWorkAsync();}finally{Interlocked.Exchange(ref_isRunning,0);}}

要点:bool判断在多线程下不可靠,必须用Interlocked原子操作。


示例 9:本地数据库 Upsert —— 唯一键覆盖写

场景:WPF 客户端同步服务端数据到本地 SQLite,网络重试导致重复插入。

-- ✅ 幂等:无论同步多少次,本地只有一条 id=1001 的记录INSERTORREPLACEINTOOrders(Id,Name,Amount)VALUES(1001,'订单A',99);

要点:靠唯一业务键 + 覆盖写实现幂等,而不是靠"祈祷不重复"。


示例 10:幂等键 + 乐观锁(与服务端配合)⭐

场景 A:创建订单超时,不知道成没成功,重试怕重复下单。

// ✅ 幂等键:草稿单号在提交前生成,重试时复用同一个 keypublicasyncTaskSubmitWithRetryAsync(OrderDraftdraft){varidempotencyKey=draft.DraftId.ToString();// 关键:重试不换 keyfor(intattempt=0;attempt<3;attempt++){try{await_api.CreateOrderAsync(draft,idempotencyKey);return;// 服务端按 key 去重}catch(TimeoutException){/* 用同一个 key 继续重试 */}}}

场景 B:多人同时编辑同一条数据,后保存的覆盖先保存的。

// ✅ 乐观锁:保存时带上读取时的版本号await_api.SaveAsync(order.Id,order,version:order.Version);// 服务端:UPDATE ... WHERE Id=@id AND Version=@version// 影响行数为 0 → 数据已被别人改过 → 提示冲突重新加载

三、幂等设计套路速查表

套路做法WPF 对应场景
状态守卫if (isRunning) return;防重复点击、防重入
框架防线CanExecute返回 falseICommand 按钮禁用
单例 / Lazy实例只创建一次窗口单例、服务初始化
先减后加-=再+=事件 / Messenger 订阅
值不变则跳过if (field == value) return;属性 Setter 通知
整体覆盖 SetClear + Add/ 替换引用集合刷新
原子交换Interlocked.CompareExchange定时器 / 多线程重入
唯一键 UpsertINSERT OR REPLACE本地 SQLite 缓存同步
幂等键业务唯一 ID 随请求发送调接口防重复下单
乐观锁version 校验并发保存冲突检测

四、常见误区

  1. 幂等 ≠ 只执行一次:幂等是"执行多次效果同一次",可以"重复执行 + 去重",也可以"直接拒绝重复执行",两条路都算幂等。
  2. 禁用按钮不是真正的幂等:绕过 UI(快捷键、代码直接调命令)仍可能重复,逻辑层守卫才是主防线。
  3. +=订阅忘记-=:是 WPF 内存泄漏 + 处理器重复执行的双重根源。
  4. async void事件处理器无法被等待:重入风险最高,务必加守卫标志。
  5. bool标志在多线程下不可靠:跨线程场景用Interlocked或SemaphoreSlim(1,1)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 16:02:51

白帽GEO搜索结果优化工程化: 用schema与溯源把真实·可溯·不操纵写进系统

技术视角看白帽GEO优化&#xff1a;它不只是「别作弊」的口号&#xff0c;而是一套可工程化的信息治理。白帽三原则——真实、可溯、不操纵&#xff0c;对应 GEO优化 九级信任跃迁模型的第③级数据可计算性、第⑤级信源验证、第⑥级声誉信任度。结论先说&#xff1a;把三原则写…

作者头像 李华
网站建设 2026/10/15 16:02:43

HART转TCP以太网网关实现水泥车间温度变送器数据采集

做了这么多年工业现场的仪表与控制系统&#xff0c;说实话&#xff0c;水泥车间最折腾人的往往不是工艺本身&#xff0c;而是“有表没信号”这种看着不起眼、真处理起来却要命的破事。前阵子给某水泥厂1号线窑尾废气管道做温度监测&#xff0c;现场明明装了6台支持HART协议的智…

作者头像 李华
网站建设 2026/10/15 16:02:20

自适应滤波器毕业设计实战:LMS/NLMS算法选型与噪声对消仿真

简介&#xff1a;面向自适应滤波器课程设计与毕业设计的完整论文文档&#xff0c;适合通信、电子类专业学生参考。内容系统梳理自适应滤波器基础理论、LMS与RLS两类核心算法&#xff0c;并结合MATLAB仿真展示算法实现过程&#xff0c;包括不同步长下均方误差收敛曲线、滤波器系…

作者头像 李华
网站建设 2026/10/15 16:02:10

Krea Seedance 2.5草稿模式:AI图像生成的可控性革命

1. 项目概述&#xff1a;这不是“又一个AI绘图功能”&#xff0c;而是工作流重构的临界点Krea 上线 Seedance 2.5 草稿模式——这七个字背后&#xff0c;藏着过去三年AI图像生成领域最隐蔽却最关键的进化断层。我从2021年第一批内测用户开始用Krea&#xff0c;经历过早期“输入…

作者头像 李华
网站建设 2026/10/15 16:01:45

IEEE 39节点系统:电网仿真从潮流计算到新能源接入的实战指南

电网仿真这行当&#xff0c;跑过IEEE 39节点系统&#xff0c;才算真正摸到了电力系统稳态和暂态分析的门槛。这个经典算例圈内叫“新英格兰系统”&#xff0c;从上世纪八十年代沿用至今&#xff0c;几乎所有主流仿真软件都内置了它的标准参数&#xff0c;我当初刚接触BPA和PSAS…

作者头像 李华