当前位置:  开发笔记 > 编程语言 > 正文

在Windows服务中使用的最佳计时器

如何解决《在Windows服务中使用的最佳计时器》经验,为你挑选了3个好方法。

我需要创建一些Windows服务,每隔N段执行一次.
问题是:
我应该使用哪个定时器控件:System.Timers.Timer或者System.Threading.Timer一个?它对某些事物有影响吗?

我问,因为我听到许多证据表明System.Timers.TimerWindows服务中的工作不正确.
谢谢.



1> Andrew Moore..:

双方System.Timers.TimerSystem.Threading.Timer会为服务工作.

您想要避免的计时器是System.Web.UI.TimerSystem.Windows.Forms.Timer,分别用于ASP应用程序和WinForms.使用这些将导致服务加载一个额外的程序集,这对于您正在构建的应用程序类型并不是真正需要的.

使用System.Timers.Timer如下例子(同样,确保使用类级别变量来防止垃圾收集,如Tim Robinson的回答所述):

using System;
using System.Timers;

public class Timer1
{
    private static System.Timers.Timer aTimer;

    public static void Main()
    {
        // Normally, the timer is declared at the class level,
        // so that it stays in scope as long as it is needed.
        // If the timer is declared in a long-running method,  
        // KeepAlive must be used to prevent the JIT compiler 
        // from allowing aggressive garbage collection to occur 
        // before the method ends. (See end of method.)
        //System.Timers.Timer aTimer;

        // Create a timer with a ten second interval.
        aTimer = new System.Timers.Timer(10000);

        // Hook up the Elapsed event for the timer.
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

        // Set the Interval to 2 seconds (2000 milliseconds).
        aTimer.Interval = 2000;
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();

        // If the timer is declared in a long-running method, use
        // KeepAlive to prevent garbage collection from occurring
        // before the method ends.
        //GC.KeepAlive(aTimer);
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
 */

如果您选择System.Threading.Timer,您可以使用如下:

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        AutoResetEvent autoEvent     = new AutoResetEvent(false);
        StatusChecker  statusChecker = new StatusChecker(10);

        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = 
            new TimerCallback(statusChecker.CheckStatus);

        // Create a timer that signals the delegate to invoke 
        // CheckStatus after one second, and every 1/4 second 
        // thereafter.
        Console.WriteLine("{0} Creating timer.\n", 
            DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = 
                new Timer(timerDelegate, autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every 
        // 1/2 second.
        autoEvent.WaitOne(5000, false);
        stateTimer.Change(0, 500);
        Console.WriteLine("\nChanging period.\n");

        // When autoEvent signals the second time, dispose of 
        // the timer.
        autoEvent.WaitOne(5000, false);
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
    }
}

class StatusChecker
{
    int invokeCount, maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal Main.
            invokeCount  = 0;
            autoEvent.Set();
        }
    }
}

这两个示例都来自MSDN页面.



2> 小智..:

不要为此使用服务.创建一个普通的应用程序并创建一个计划任务来运行它.

这是最常见的最佳做法. Jon Galloway同意我的看法.或者也许是相反的方式. 无论哪种方式,事实是创建一个Windows服务来执行从计时器运行的间歇性任务不是最好的做法.

"如果您正在编写运行计时器的Windows服务,则应重新评估您的解决方案."

-Jon Galloway,ASP.NET MVC社区项目经理,作者,兼职超级英雄


如果您的服务打算全天运行,那么服务可能是有意义的而不是计划任务.或者,拥有一项服务可能会简化基础架构组的管理和日志记录,而该基础架构组并不像应用程序团队那样精明.然而,质疑假设需要服务是完全有效的,并且这些负面评级是不值得的.两者都是+1.
我讨厌在这里跋涉泥潭,但我必须稍微捍卫MR.我在公司运行的几个关键应用程序是Windows控制台应用程序.我使用Windows任务计划程序来运行所有这些程序.现在至少有5次,我们遇到了一个问题,即调度服务以某种方式"混淆"了.任务没有执行,有些处于一种奇怪的状态.唯一的解决方案是重新启动服务器或停止和启动Scheduler服务.如果没有管理员权限而且在生产环境中无法接受,那么我无法做到.只需我0.02美元.
它实际上发生在我的几台服务器上(目前为止3台).不会说这是常态.只是说有时候实施自己的做事方法也不错.
@MR:我不是传道者,我是一个现实主义者.而现实告诉我,计划任务并非"极其错误".事实上,这取决于你作为声称支持它的人.否则,你所做的只是传播恐惧,不确定和怀疑.
@mr废话.计划任务是操作系统的核心部分.请保持你的FUD给自己.
@Nick:取决于.例如,如果您需要一个人们可以更改时间表的网站,那么就需要一项服务.或者,如果每次安装配置一次,或者很少配置,那么计划任务就可以了.

3> Tim Robinson..:

任何一个都应该工作正常.实际上,System.Threading.Timer在内部使用System.Timers.Timer.

话虽如此,很容易误用System.Timers.Timer.如果你没有将Timer对象存储在某个变量中,那么它很容易被垃圾收集.如果发生这种情况,您的计时器将不再发射.调用Dispose方法来停止计时器,或使用System.Threading.Timer类,这是一个稍好的包装器.

到目前为止你看到了什么问题?

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有