指数退避需用retry_count计算base_delay * (2^retry_count),并以max_delay(如5s)截断,每次重试前检查总超时。

怎么用 std::this_thread::sleep_for 实现指数退避
核心是每次失败后等待时间翻倍,但不能无限制增长。直接写 sleep_for(1s)、sleep_for(2s) 这种硬编码会失去“可配置”意义。
- 用一个整数
retry_count记录当前重试次数,初始为 0 - 等待时长按
base_delay * (2 ^ retry_count)计算,比如 base_delay =100ms - 必须加最大上限,否则第 10 次重试就要等约 100 秒——实际中常设
max_delay = 5s - 别忘了在每次重试前检查是否超时总时限,否则可能卡死
示例逻辑:
auto delay = std::min(base_delay * (1LL << retry_count), max_delay);<br>std::this_thread::sleep_for(std::chrono::milliseconds(delay));
为什么要把重试逻辑封装成函数模板而不是宏或普通函数
因为你要适配不同返回类型(bool、std::expected<t e></t>、甚至带异常的 lambda),且不想重复写 sleep + 循环结构。
- 用模板参数
F接受任意可调用对象,返回值统一用std::optional<t></t>或std::expected<t e></t>表达成功/失败 - 避免宏:宏无法做类型推导,调试信息差,且容易和外部变量名冲突
- 避免普通函数:没法自动推导
T,每次都要显式写retry<int>(…)</int>,不直观 - 注意:如果被调用函数可能抛异常,模板里得包一层
try/catch,否则异常直接跳出重试循环
std::chrono::steady_clock 和 system_clock 选哪个
必须用 std::chrono::steady_clock。系统时间可能被 NTP 调整或手动修改,导致重试间隔错乱甚至跳过重试。
立即学习“C++免费学习笔记(深入)”;
-
steady_clock单调递增,不受系统时间变更影响,适合计时 - 判断是否超时总时限时,应记录起始
steady_clock::now(),每次循环计算差值 - 不要用
time(nullptr)或system_clock::to_time_t做超时判断——它们不是单调的 - 如果需要日志里打“绝对时间”,再额外用
system_clock格式化,但控制逻辑只依赖steady_clock
配置项怎么暴露才不容易出错
把重试参数做成结构体传入,比零散传 5 个参数更安全,也方便后续扩展(比如加 jitter)。
- 结构体字段建议命名清晰:
max_retries、base_delay_ms、max_delay_ms、total_timeout_ms - 构造时做基本校验:比如
base_delay_ms > 0、max_retries >= 0,非法值直接throw std::invalid_argument - 别用全局变量或静态配置类存这些值——多线程下易踩竞态,尤其
retry_count是 per-call 的 - jitter(随机扰动)可选加,防止大量请求在退避后同时涌向下游,加法 jitter 比乘法更易控范围
真正难的不是算指数,是让配置能被测试覆盖、被不同模块复用、且不因时钟跳变或异常路径失效。这些细节漏掉一个,上线后就只能靠日志猜问题。








