如何可靠地每秒调用一个函数X次?

时间:2019-03-03 14:38:23

标签: java math

我正在尝试编写一个支持设置tps值的线程库。但是,我有一个问题,当tps是例如15时,滴答声持续的平均时间将是66667 ms。由于一个线程只能休眠整毫秒,因此我的解决方案是创建一个查找表,其中所有值的总和为1000毫秒。

因此,如果我想每秒钟有15个滴答声,我只会在0到14之间进行for循环,并在表中查找最大睡眠时间。我的问题是如何计算查找表中的值?

我的方法如下:

int tps = 15;
int[] sleepTime = new int[tps];

float tickTime = 1000.0f / tps;
float increment = 1.0f - (tickTime - (int) tickTime);
float overflow = 0;
int c = 0;
for (int n = 0; n < tps; n++) {
    if (overflow >= 1) overflow = 0;
    sleepTime[n] = (int) tickTime + (int) Math.ceil(overflow);
    c += sleepTime[n];
    overflow += increment;
}

System.out.println(Arrays.toString(sleepTime));
System.out.println("Complete sleep time: " + c);

这对于15之类的较小值来说效果很好,但是当我希望具有31 tps之类的较高值时,所有计算值的总和大于1000(31为1007)。

2 个答案:

答案 0 :(得分:1)

您可以逐步从剩余的睡眠时间中减去整数除法的值:

int[] tps(int tps) {
    int[] sleepTimes = new int[tps];
    for (int i = 0, remainder = 1000; i < tps; i++) {
        int sleepTime = remainder / (tps - i);
        sleepTimes[i] = sleepTime;
        remainder -= sleepTime;
    }
    return sleepTimes;
}

tps(3)的示例评估:

  • i = 0,余数= 1000,sleepTime = 333
  • i = 1,余数= 667,sleepTime = 333
  • i = 2,余数= 334,sleepTime = 334
  • i = 3(余数= 0,sleepTime = N / A)

要使下限和上限值均匀分布,可以执行以下操作:

int[] tps(int tps) {
    int[] sleepTimes = new int[tps];
    int low = 1000 / tps; // the floored value
    Arrays.fill(sleepTimes, low);
    int mod = 1000 % tps; // number of ceiled values to insert
    if (mod > 0) {
        int high = low + 1; // the ceiled value
        float rate = tps / (float) mod; // the insertion rate
        for (int i = 0; i < mod; i++) {
            sleepTimes[Math.round(i * rate)] = high;
        }
    }
    return sleepTimes;
}

tps(21):[ 48 47 48 48 47 48 48 47 48 47 48 48 47 48 47 48 < / strong>, 48 47 48 48 47 ] < / p>

答案 1 :(得分:0)

Thread.sleep(long millis, int nanos)睡眠毫秒和纳秒。 因此,计算出确切的睡眠时间,然后开除一名工人(在另一个线程中)并重新入睡。这意味着工人的执行时间无关紧要。

为避免漂移错误,请根据开始时间和计数器进行睡眠计算。每次知道之后,线程都会少睡觉一些,以补偿处理自己的睡眠计时器所需的少量时间。