【问题标题】:Timing a method to repeat every N seconds for M hours定时一种方法,每 N 秒重复一次,持续 M 小时
【发布时间】:2016-10-17 01:46:58
【问题描述】:

所以我有一个必须每 30 秒运行一次长达 2 小时的方法。

我的代码是:

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {

            Stopwatch s30 = new Stopwatch();
            s30.Start();
            while (s.Elapsed < TimeSpan.FromSeconds(30))
            {
                //Method To Run
            }
            s30.Stop();
        }
        s.Stop();
    });
}

我做的是否正确(即达到上述时间间隔)还是有正确和/或更多时间精确的方法来做?

我需要知道,因为我从特定 url 访问数据,有时我得到空值,可能是由于访问过于频繁。

谢谢。

编辑:This 给了我一个不使用计时器的想法,没有具体原因。

【问题讨论】:

  • 你可以使用定时器
  • 为什么不简单地使用 Timer 类之一?
  • 你可以使用 Thread.Sleep,但我并不是说它更好
  • 这并不是所有代码都运行 30 秒。它只是一遍又一遍地运行了2个小时。请注意,一段时间后停止和等待一段时间后再次运行是两件不同的事情,但是您的两个 while 循环基本相同。

标签: c#


【解决方案1】:

This 给了我一个不使用计时器的想法,没有具体原因。

Timer 完全适用于这个用例。链接问题中的问题是秒表与计时器的精度。您不需要那种精确度(我假设),所以使用Timer 没有任何问题。

由于您声称“从特定 URL 访问数据”,延迟的差异可能会抵消使用 Stopwatch 对精度的任何改进。

我会专注于找出为什么你会得到空值,并决定如何处理它。

【讨论】:

  • 看来我的逻辑不正确。我需要嵌套计时器。
  • 您的意思是“N hours”部分?您可以,或者只使用静态 DateTime 值来了解您何时开始。当您处理大量时间时,精度就更不用说了。
  • 我同意计时器是比睡眠循环更好的选择。但是,我强烈建议不要依赖DateTime 来计算经过的时间。如果他恰好在夏令时更改的早上 1:00 开始这段代码,那么他最终可能会导致计时器运行时间比应有的时间长一个小时,或者比应有的时间短一个小时。或者,如果用户更改时间。最好使用StopWatch 来计算经过的时间。
【解决方案2】:

如果您要使用 StopWatch,那么您需要执行以下操作以使其在两次运行之间实际等待 30 秒。

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {
            Stopwatch s30 = new Stopwatch();
            s30.Start();
            //Method to run
            while (s.Elapsed < TimeSpan.FromSeconds(30))
            {
            }
            s30.Stop();
        }
        s.Stop();
    });
}

但您可以将内部的 StopWatch 替换为对 Thread.Sleep 的调用,并避免 CPU 达到峰值。

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {
            //Method to run
            Thread.Sleep(TimeSpan.FromSeconds(30));
        }
        s.Stop();
    });
}

请注意,第二个在运行之间设置了 30 秒的间隔。这意味着您的方法运行所需的时间不包括在运行之间的时间中,这与第一次不同。

【讨论】:

  • 简单、轻松、完美!
【解决方案3】:
private int x = 0;
public Form1 ()
{
    InitializeComponent();
}

private void button1_Click ( object sender, EventArgs e )
{
    InitTimer();
}

private void timer1_Tick ( object sender, EventArgs e )
{
    bool s = IsFinished();
    if (s == true)
        textBox1.Text = "true";
}

private void InitTimer ()
{
    timer1 = new Timer();
    timer1.Tick += new EventHandler(timer1_Tick);
    timer1.Interval = 3000; //30000 is 30 seconds
    timer1.Start();
}
private bool IsFinished ()
{
    if (++x == 2) //1 min
    {
        timer1.Stop();
        return true;
    }
    else return false;
}

这是一种真正快速的方法,可以通过计时器和计数控制多次运行您的函数或方法。在How do I measure how long a function is running? 中,我会说使用秒表可能比我的脏计数器更精确和高效,但老实说,秒表和计时器之间的时间差异最多可以忽略不计,除非你需要优于毫秒的时间差异。

【讨论】:

  • 您的代码有错误。 Interval 设置为 3 秒而不是 30 秒。
  • 阅读区间语句旁边的注释。完全没有错误。
  • 好吧,好吧。但是IsFinished 中的评论不正确。如前所述,计时器将运行 6 秒,而不是一分钟。
  • 看在上帝的份上,这是一个小程序,用来做他想做的事。我写它是为了让它每隔 3 秒而不是 30 秒,注意评论 30 秒,就像他想要的那样。还要注意那里写有//1 min 的评论。如果他想改变它,他会在那里做出改变。我的回答绝对没有问题。
猜你喜欢
  • 1970-01-01
  • 2018-01-06
  • 1970-01-01
  • 2011-03-24
  • 2022-12-11
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多