我应该使用 Sleep 还是 Timer?

6

我有两种选择,使用计时器或者使用休眠,我需要在方法完成后每3秒调用一次该方法。以下是一个基本示例来演示我的意思:

public static void Main()
{
    new Thread(new ThreadStart(fooUsingSleep)).Start();

    callToMethodAfterInterval(new Action<object, ElapsedEventArgs>(fooUsingTimer), 3000);
}

public static void fooUsingSleep()
{
    Console.WriteLine("Doing some consuming time work using sleep");
    Thread.Sleep(3000);
    fooUsingSleep();
}

public static void fooUsingTimer(object dummy, ElapsedEventArgs dummyElapsed)
{
    Console.WriteLine("Doing some consuming time work usning timer");
    callToMethodAfterInterval(new Action<object, ElapsedEventArgs>(fooUsingTimer), 3000);
}

public static void callToMethodAfterInterval(Action<object,ElapsedEventArgs> inMethod, int inInterval)
{
    System.Timers.Timer myTimer = new System.Timers.Timer();
    myTimer.Elapsed += new ElapsedEventHandler(inMethod);
    myTimer.Interval = inInterval;
    myTimer.AutoReset = false;
    myTimer.Start();
}

我的问题是:
1)我能否更优雅地编写带有定时器的代码?这意味着从fooUsingTimer方法中删除对callToMethodAfterInterval方法的调用,将定时器缩短为一两行,并从fooUsingTimer的声明中删除虚拟变量?
2)我知道sleep不是忙等待(http://www.codeproject.com/KB/threads/ThreadingDotNet.aspx),所以我找不到在此处使用定时器选项的理由,因为sleep更简单。哪个更好,定时器版本还是sleep版本?
3)我知道Timers.timer是线程安全的,它能帮助我实现想要的行为吗?
谢谢。
3个回答

3

您是否意识到fooUsingSleep一遍又一遍地调用自身?最终会导致堆栈溢出。

如果您正在使用计时器,那么可以简单地使用以下代码:

    System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
    t.Interval = 3000;
    t.Tick += new EventHandler((o,ea) => Console.WriteLine("foo"));

+1 对于优雅的解决方案,但它会导致堆栈溢出吗?我看不出来,在你的解决方案中,方法可以在最后一个方法完成之前被调用,这可能会导致难以发现的错误,因此我没有将其标记为答案。 - Delashmate
1
它们在同一线程上运行,因此在最后一个完成之前不能调用它。如果从fooUsingSleep()内部调用fooUsingSleep(),则您的解决方案最终会导致堆栈溢出,因为在每个方法调用时,执行上下文都会被推送到堆栈上,而堆栈容量不是无限的。 - Axarydax
好的,现在我明白你提到的堆栈溢出了 :) - Delashmate

2

您的程序的实际上下文也很重要。

sleep选项会"浪费"一个线程,在小型控制台应用程序中不是问题,但通常不是一个好主意。

您不需要重新启动计时器,以下内容将继续保持运行:

    static void Main(string[] args)
    {
        var t = new System.Timers.Timer(1000);
        t.Elapsed += (s, e) => CallMeBack();
        t.Start();

        Console.ReadLine();
    }

1
我想指出的是,我认为这不完全是原本意图要做的事情——它正在执行长时间运行的任务,然后在完成后3秒再次运行——而你的程序将每秒运行一次? - Paddy
@Paddy,没错,我假设这是一个相对简短的任务。原帖作者应该说明清楚。 - H H
我不希望在其他对foo的调用完成之前就调用foo选项。 - Delashmate
@Delas:如果Foo()函数的执行时间接近3秒,那么最好使用某种守卫标志。 - H H
听起来不错,标记为答案。我也喜欢你在foo声明中消除了声明虚拟变量的需要。 - Delashmate

0

休眠会起到作用,而计时器则是为了这个特定目的而设计的,约定俗成更好,通常会使您的代码更易于理解。


我该如何更优雅地编写计时器部分? - Delashmate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接