1

假设我想每小时运行一次任务,但在一小时内的可变时间运行。它不一定是真正随机的。例如,我只是不想在每小时的最开始做这件事。我只想每小时做一次。

这消除了几种明显的方法,例如随机睡 30 到 90 分钟,然后再睡。该任务有可能(而且很可能)连续运行多次,睡眠时间不超过 30 分钟。

我正在考虑的方法是这样的:每小时对一小时的 Unix 时间戳进行哈希处理,然后将结果修改为 3600。将结果添加到一小时的 Unix 时间戳,这就是任务应该运行的时刻。在伪代码中:

while now = clock.tick; do
  // now = a unix timestamp
  hour = now - now % 3600;
  hash = md5sum(hour);
  the_time = hour + hash % 3600;
  if now == the_time; then
    do_the_work();
  end
end

我确信这会满足我的要求,但我认为把这个问题抛出去看看其他人有什么想法会很有趣!

4

3 回答 3

1

在接下来的一小时内工作,只需在该小时内随机选择一分钟。

也就是说,为下一个间隔选择一个随机时间进行工作;如果工作已从前一个间隔结转,则这可能与当前间隔(小时)相同。

“睡觉时间”只是到那时为止的时间。如果随机时间在现在之前,这也可以在结转情况下“立即”执行:这将确保每小时选择一个随机时间除非工作需要超过一个小时。

不要让它变得比它必须的更复杂 - 没有理由在random这里散列或以其他方式搞砸。这就是“企业”解决方案(如 SharePoint 计时器(带有每小时计划))的工作方式。

于 2013-02-12T01:05:21.207 回答
0

我已经部署了我建议的解决方案,并且运行良好。例如,每分钟一次,我从我正在监视的进程中采样一些信息,但我在一分钟内的不同时间进行采样。我在 Go 代码中创建了一个 Timestamp 类型的方法,称为 RandomlyWithin,如下所示:

func (t Timestamp) RandomlyWithin(dur Timestamp, entropy ...uint32) Timestamp {
    intervalStart := t - t % dur
    toHash := uint32(intervalStart)
    if len(entropy) > 0 {
        toHash += entropy[0]
    }
    md5hasher.Reset()
    md5hasher.Write([]byte{
        uint8(toHash >> 24 & 255),
        uint8(toHash >> 16 & 255),
        uint8(toHash >> 8 & 255),
        uint8(toHash & 255)})
    randomNum := binary.BigEndian.Uint32(md5hasher.Sum(nil)[0:4])
    result := intervalStart + Timestamp(randomNum)%dur
    return result
}
于 2013-02-13T11:11:04.143 回答
0
  1. 安排您的任务(使用 cron 等)在每小时的顶部运行。

  2. 在你的任务开始时,随机睡眠一段时间,从 0 到 (60 - (你的任务的估计运行时间+一个软糖因素)) 分钟。

  3. 如果您不希望您的任务同时运行两次,您可以使用 pid 文件。该任务可以在睡眠后检查此文件并等待当前正在运行的任务完成,然后再重新开始。

于 2013-02-12T01:05:06.800 回答