数量呈指数增长,达到最大值

时间:2014-12-15 09:14:55

标签: c# algorithm math

我正在尝试构建一个发送电子邮件的重试机制。我希望它是可配置的,以便管理员可以指定两者;

  • 重试次数(间隔)
  • 放弃前的最大秒数

进一步的要求是每次重试之间等待的秒数以指数方式(或遵循其他几何序列)增加到最大值。

另一种描述问题的方法是:如何将最大秒数划分为X个间隔,其间每个间隔比其前一个间隔指数大?

我不确定这是否可以使用纯粹的数学表示来表达,如果不是C#中的例子会受到欢迎。但是,我真的只是在寻找这里的逻辑,所以如果它得到了很好的解释,我确信任何语言都可以轻松翻译。

5 个答案:

答案 0 :(得分:3)

一些数学:让变量T(总时间),N(重试次数),t(第一次尝试的时间)和e(指数) 。每次尝试都需要:t*1t*et*e*et*e*e*e等。

所以总时间可写为T = t*e^0 + t*e^1 + t*e^2 +.. + t*e^N重写:T = t*(e^0+e^1+e^2 .. + e^N)。我们可以将sum of powers计算为:sum = (e^N-1)/(e-1)

由于TNe,我们可以将t计算为:t = T/((e^N-1)/(e-1))

要计算i次迭代使用的时间:ti = t*e^i

例如,给定T = 124(s),N = 5(尝试)并且e = 2,第一个间隔将是124/((2^5-1)/(2-1)) = 4s。以下间隔将是:

  • 第0个间隔:4s(t * e ^ 0)
  • 第一个间隔:4 * 2 = 8s(t * e ^ 1)
  • 第二间隔:8 * 2 = 4 * 2 * 2 = 16s(t * e ^ 2)
  • 第3个间隔:16 * 2 = 4 * 2 * 2 * 2 = 32s(t * e ^ 3)
  • 第4个间隔:32 * 2 = 4 * 2 * 2 * 2 * 2 = 64s(t * e ^ 4)

等待124秒的总时间。

抱歉格式化。对于Mathematics,这个问题可能会更好。

计算所有间隔的代码是:

public static void TestFunction(int max, int numIntervals) {

    List<double> intervals = new List<double>();

    double exponent = 2;

    double n = Math.Pow(exponent, numIntervals) - 1;
    double d = exponent - 1;

    double t = max / (n / d);

    for (int x = 0; x < numIntervals; x++) {
        double interval = t * Math.Pow(exponent, x);
        intervals.Add(interval);
    }

}

答案 1 :(得分:1)

我不确定这个答案有多有用,但创作肯定很有趣。这个答案有些不同的原因是它计算了用于指数计算时间间隔的基础。

因此输入是总时间以及将时间跨度划分为多个时间间隔。指定第一个间隔的长度,挑战是计算剩余的间隔,以确保它们呈指数增长并总和为总时间。

这可以表示为数学方程式:

t∙x 0 + t∙x 1 + ... + t∙ x n = T

t 是第一个间隔的长度, T 是总时间。 n 是间隔数, x 是未知基数。

假设 x 不是1,则可以将此等式重写为多项式方程的标准形式:

x n - r∙x + r - 1 = 0

其中 r = T / t 是总时间与第一个间隔长度之间的比率。

据我所知,这个方程没有通用的解决方案,但可以使用数值分析库中的算法来解决。我从Math.Net Numerics上的NuGet库中选择了Newton-Raphson算法。对于该算法,需要多项式的一阶导数,这是

n∙x n - 1 - r

将所有这些组合起来创建一系列指数增长的时间跨度等待:

IEnumerable<TimeSpan> ExponentialTimeSpans(TimeSpan firstTimeSpan, TimeSpan totalTimeSpan, Int32 count) {
  var ratio = totalTimeSpan.TotalSeconds/firstTimeSpan.TotalSeconds;
  var @base = RobustNewtonRaphson.FindRoot(
    x => Math.Pow(x, count) - ratio*x + ratio - 1,
    x => count*Math.Pow(x, count - 1) - ratio,
    1d + 1E-8, // Assume that base is > 1
    100d // Arbitrary (but BIG) upper limit on base
  );
  for (var i = 0; i < count; i += 1)
    yield return TimeSpan.FromSeconds(firstTimeSpan.TotalSeconds*Math.Pow(@base, i));
}

请注意,您可以轻松地提供没有解决方案的输入,这将导致抛出异常。但是,任何基于原始问题陈述的合理输入都应按预期工作。

答案 2 :(得分:0)

可能会出现以下情况?

var time_in_seconds = 10000; // usually done in milliseconds, so lets say 10 sec.

// if email fails:
time_in_seconds *= 10; 
// So, next will be 100, 1000, etc. & you get your exponential increment.

答案 3 :(得分:0)

第一步 - 一个简单的解决方案 - 反向工作! (减少率为50%)

我需要在10秒内完成128秒。

Interval :  Time (Of occurrence)
1        :  128
2        :  64
3        :  32
4        :  16
5        :  8
6        :  4
7        :  2
8        :  1
9        :  1/2
10       :  1/4

注意:以上工作正常(保持在X下,只是从X / 2开始)。下面,没有那么多。这种技术可以迭代地应用于找到一个好的&#39;解决方案虽然现在。

很好,但如果我们需要最低限度会怎么样?可能不需要在开始时重试之间的1/128秒。所以我们需要做的是改变指数。

现在,上述内容可以写成result = 1/4 * 2^9或更一般result = startingInterval * 2^(n-1)。但是我们知道我们想要的结果,所以我们需要重新安排这个公式。

(result/startingInterval)^(1/(n-1)) = base

具有以上价值: (128/(1/4))^(1/(10-1)) = base = 2

或换句话说,要获得128秒的总时间,以1/4秒的间隔开始并使用10次尝试(包括第一次),那么我们需要每次尝试将间隔之间的长度增加2倍。

答案 4 :(得分:-1)

声明最大阈值以及为每次重试添加的偏移量。

int maxRetryCount = 5;
int offSet = 10000;
int currRetryCount = 0;
int waitTime = 1000; //default value

while(currRetryCount < maxRetryCount)
{
    try
    {
        //Send Email 
        // break out once the email is send
        break;
    }
    catch
    {
        //Wait for a while
        Thread.Sleep(waitTime);

        //increase the wait time for next time
        waitTime += offSet;
        currRetryCount++;
    }
}

此处代码最多会尝试5次发送电子邮件,每次等待时间将增加10秒。