【问题标题】:What is the best way to call/start a Windows Service every x seconds?每 x 秒调用/启动 Windows 服务的最佳方式是什么?
【发布时间】:2009-05-15 06:05:00
【问题描述】:

我有一个 Windows 服务,它基本上是访问邮箱和阅读电子邮件。我试图找出每 x 秒检查一次邮箱的最佳方法。

一种方法是调用 Thread.Sleep,然后再次调用 Start 方法,例如

protected override void OnStart(string[] args)
{
    // get config settings
    CheckMailbox();
}

public void CheckMailbox()
{
    int x = 5000;

    // do stuff

    Thread.Sleep(x);
    CheckMailbox();
}

不确定这是否是最好的方法。为了进一步探索这一点,我知道您可以通过 WCF 公开服务来调用 Windows 服务。在这种情况下,如果一个 Web 应用程序调用 Process 来启动,会有冲突的线程我正确吗?那我该如何处理呢?我每次都必须创建一个新线程并将其放入队列中吗?

【问题讨论】:

    标签: asp.net windows-services wcf


    【解决方案1】:

    睡觉通常是个坏主意。除此之外,这意味着您不会快速响应 Stop 事件。

    您应该使用Timer。有两种适用于服务:

    在每种情况下,您基本上都会在每次计时器“滴答”以及您希望它何时触发时说出您想要发生的事情。

    我的线程教程有一个section explaining some of the differences between available timers

    我不确定您的 WCF 问题,但我认为您的 Web 服务不会显式启动该服务 - 它只是通过 WCF 与其联系。是的,您可能需要小心线程。您需要注意的具体内容取决于 WCF 服务所公开的内容。

    【讨论】:

    • +1 - 啊,好点子!在睡眠时,服务不会对停止事件做出反应,这是真的。
    • 使用线程计时器,假设我每 10 秒检查一次邮箱,打开和处理需要超过 10 秒的时间,这将有多个线程同时运行正确吗?
    • +1 计时器很有用! @mickyjtwin:如果你使用 System.Timers.Timer 它有 Start 和 Stop 方法,所以你可以调用 Stop,处理你的邮件,然后调用 Start。这样,您将在处理完邮件后等待 x 秒,直到下次检查。但是,在您建议的情况下,我认为您不会获得并行线程; Tick 应该在创建计时器的线程上调用,而不是在新线程上。
    • 我使用了一个示例,其中 Threading.Timer 每 2 秒调用一次,并且回调休眠了 10 秒。每 2 秒在一个新线程上创建回调。如果该过程花费的时间超过 2 秒,则新线程将执行并行处理。你如何使用非线程定时器每隔 x 秒调用一次?
    • 如果过程花费的时间比间隔时间长,您希望发生什么?很容易让它在每次迭代结束时等待间隔时间 - 只需使用 Timers.Timer,将 AutoReset 设置为 false,然后在每次迭代结束时调用 Start()。
    【解决方案2】:

    基本 System.Threading.Timer 代码:

    // Class level variable in the Windows Service:
    private System.Threading.Timer timer;
    
    // This is in the constructor for a Windows Service.
    // interval would be the time in milliseconds in between ticks.
    // 0 is how long until it should start.
    timer = new Timer(new TimerCallback(TimerElapsed), null, 0, interval);
    
    // The TimerCallback in the Windows Service:
    private void TimerElapsed(object o)
    {
        // Do email stuff here.
    }
    

    【讨论】:

      【解决方案3】:

      如果您想让它作为服务运行(在后台,没有任何人登录),是的,这是一种方法。

      另一种方法是有一个 Timer,它每 5 秒左右调用一次它的“Tick”事件处理程序。

      或者,如果您的检查不那么频繁,您也可以创建一个命令行控制台应用程序并将其安排为 Windows 中的“计划任务”。

      马克

      【讨论】:

        【解决方案4】:

        您的代码存在每次调用都添加到调用堆栈的问题,因为您从自身内部调用该方法。在某些时候你会得到一个堆栈溢出异常。一种等待是在“等待线程”上调用另一种方法,该方法将在一定时间后返回信号:

        private void CheckMailBox()
        {
            _waitHandle = new AutoResetEvent(true);
            while (_waitHandle.WaitOne())
            {
                // do the mail checking
                ((IDisposable)_waitHandle).Dispose();
                _waitHandle = new AutoResetEvent(false);
                ThreadPool.QueueUserWorkItem(WaitSomeTime, 2000);
            }
        
        }
        
        private void WaitSomeTime(object state)
        {
        
            Thread.Sleep((int)state);
            _waitHandle.Set();
        }
        

        【讨论】:

          【解决方案5】:

          除了使用计时器之外,一个可能的增强功能是在您的服务中使用调度组件。然后,您可以将您的服务设置为访问您邮箱的代码的主机。

          Quartz.NET 是一个可以做到这一点的开源调度组件。它允许您完全按照您的需要设置计划,并且非常易于使用。

          【讨论】:

            【解决方案6】:

            好的,虽然您的时间问题已经得到了很好的处理(我同意上述大部分内容),但我可以提供一些有关 WCF 的信息。 WCF 服务只是托管在应用程序域中。该域可以是 Windows 窗体、控制台应用程序、ASP.net,在这种情况下,可以是 Windows 服务。

            所以从某种意义上说,您不是通过 WCF 公开 windows 服务,而是更多地在 Windows 服务中托管 WCF 服务强>应用领域。我建议在过渡到 Windows 服务之前,在 windows 表单 中测试您的服务(包括计时器对象)。更易于调试和测试。

            托管的 WCF 服务实际上在其自己的线程中运行:

                serviceType_MyEmailer = typeof(MyEmailerServiceType);
                ServiceHost host_MyEmailer;
            
            
                host_MyEmailer = new ServiceHost(serviceType_MyEmailer);
            

            在线查找“DerivativesCalculatorService”示例。向您展示如何在代码中托管 WCF 服务。

            这里的计时技巧在于您的服务本身。您可以将您的服务类创建为一个立即初始化的单例类,并在其初始化时启动它的 Timer 对象(如其他答案所示)。

            通过这种方式,您的 WCF 服务将拥有您的类的持久实例,其 Timer 对象会静默关闭。将所有这些都托管在 Windows 服务中,您就完成了。

            希望这会有所帮助。

            【讨论】:

              猜你喜欢
              • 2016-01-04
              • 1970-01-01
              • 1970-01-01
              • 2013-03-27
              • 1970-01-01
              • 1970-01-01
              • 2017-02-09
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多