Maui Blazor 中文社区 QQ群:645660665

指数退避: 一种常用于网络请求重试的策略

"指数退避"(Exponential Backoff)是一种常用于网络请求重试的策略。其核心思想是:每当操作失败并需要重试时,不是立即重试,而是等待一段时间再重试,并且每次重试之间的等待时间呈指数级增长(通常是成倍增加)。

实现指数退避的逻辑:
await Task.Delay(delayMilliseconds * attempt);
这里,每重试一次,等待时间就会增加(第1次等待1倍,第2次2倍,第3次3倍……)。这样做的好处是可以减轻服务器压力,避免因频繁重试导致网络拥堵或服务雪崩。

常见的指数退避公式为:
等待时间 = 基础延迟 * 2^重试次数

上面的实现是线性递增(delayMilliseconds * attempt),如果要严格指数退避,可以改为:
await Task.Delay(delayMilliseconds * (int)Math.Pow(2, attempt));

总结:
指数退避就是每次重试等待的时间越来越长,常用于处理网络异常、请求超时等场景,提高系统的健壮性和容错能力。

C# 中实现指数退避的具体代码示例:

using System;
using System.Net.Http;
using System.Threading.Tasks;

public static class RetryHelper
{
    /// <summary>
    /// 使用指数退避策略重试异步操作
    /// </summary>
    /// <typeparam name="T">返回类型</typeparam>
    /// <param name="action">要执行的异步操作</param>
    /// <param name="maxRetries">最大重试次数</param>
    /// <param name="baseDelayMilliseconds">基础延迟(毫秒)</param>
    /// <returns>操作结果</returns>
    public static async Task<T?> RetryWithExponentialBackoffAsync<T>(
        Func<Task<T?>> action,
        int maxRetries = 5,
        int baseDelayMilliseconds = 500)
    {
        int attempt = 0;
        while (true)
        {
            try
            {
                return await action();
            }
            catch (Exception ex) when (attempt < maxRetries)
            {
                attempt++;
                int delay = baseDelayMilliseconds * (int)Math.Pow(2, attempt - 1);
                Console.WriteLine($"第{attempt}次重试,等待{delay}ms,异常信息: {ex.Message}");
                await Task.Delay(delay);
            }
        }
    }
}

用法示例:

// 假设有一个可能抛出异常的异步方法
async Task<string?> GetDataAsync()
{
    // 这里模拟网络请求
    throw new HttpRequestException("网络错误");
}

// 调用带指数退避的重试方法
var result = await RetryHelper.RetryWithExponentialBackoffAsync(GetDataAsync);

说明:

  • 每次重试等待时间为 baseDelayMilliseconds * 2^(attempt-1),即 500ms, 1000ms, 2000ms, 4000ms, ...
  • 只要未超过最大重试次数,遇到异常就会指数级延迟后重试。
  • 你可以根据实际需求调整最大重试次数和基础延迟时间。

如需将你现有的 RetryAsync 方法改为严格的指数退避,只需将 await Task.Delay(delayMilliseconds * attempt); 替换为:

await Task.Delay(delayMilliseconds * (int)Math.Pow(2, attempt - 1));

这样即可实现标准的指数退避。

posted @ 2025-06-14 04:59  AlexChow  阅读(249)  评论(0)    收藏  举报