繁体   English   中英

数量成倍增加,达到最大值

[英]Exponentially increasing number towards maximum

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

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

另一个要求是每次重试之间要等待的秒数成倍增加(或遵循某些其他几何顺序),直到最大值。

描述问题的另一种方式是: 如何将最大秒数划分为X个间隔,其中每个间隔都比前一个间隔成倍增长?

我不确定是否可以使用纯数学表示形式来表示,否则就不会欢迎使用C#中的示例。 但是,我实际上只是在这里寻找逻辑,因此,只要它有充分的解释,我相信任何语言都可以轻松翻译。

一些数学运算:让变量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 = (e^N-1)/(e-1)

因此给定TNe ,我们可以将t计算为: t = T/((e^N-1)/(e-1))

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

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

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

总等待时间为124秒。

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

计算所有间隔的代码为:

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);
    }

}

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

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

可以用数学公式表示:

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是总时间与第一个间隔的长度之间的比率。

据我所知,该方程式没有通用解,但可以使用数值分析库中的算法求解。 我从NuGet上可用的Math.Net Numerics库中选择了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));
}

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

像下面这样的东西?

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.

第一步-一个简单的解决方案-反向进行! (减少幅度为50%)

我需要在128秒内调整10个间隔。

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开始)。 下面,不是很多。 尽管目前,可以迭代地应用此技术以找到“好的”解决方案。

很好,但是如果我们需要最低限度的价格怎么办? 重新开始之间的两次重试之间不需要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 / 4s的间隔开始并使用10次尝试(包括第一次尝试),则我们需要将间隔之间的长度每次尝试增加2倍。

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

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秒。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM