2016-09-19 66 views
0

我在.Net Framework 4.0中编写了一个Windows服务,我需要安排一个循环任务。新任务只能在前一个任务完成时运行,所以没有任何并行任务... 我的所有任务都发生在同一个对象(WCF Channel工厂)上。 完成一项任务需要将近2秒钟,并且可能每2秒或每小时安排一次。 我的约束是有这样的Windows服务作为无形/尽可能轻的内存和处理器使用的角度来看...C#在高效的Windows服务中安排循环任务的最佳方法

我已经找到了这些2种方式:

  • 使用System.Timers.TimerAutoreset假=>我已经到 实施ElapsedEventHandler,并通过我的共享对象(WCF 通道工厂)
  • 使用永无止境的循环:不知道MEM/proc中使用的 那个状态,但没有线程方面的照顾的。

有什么建议吗?

谢谢,祝你有美好的一天!

+0

以下是我使用TPL实施重复任务的一种方式。它可能会给你另一个想法/路线。 http://stackoverflow.com/q/39457595/2985796 – KDecker

回答

2

对我来说很好:Im开始计时一次,然后在Tick方法中,我将安排下一次Tick调用。就像这样:

public void SetTimer() 
{ 
    // this is System.Threading.Timer, ofcource 
    _timer = new Timer(Tick, null, _interval, Timeout.Infinite); 
} 

private void Tick(object state) 
{ 
    try 
    { 
     // do your stuff 
    } 
    finally 
    { 
     _timer?.Change(_interval, Timeout.Infinite); 
    } 
} 

// dont forget to dispose your timer. 
+0

感谢Tym,我想我应该有新的System.Threading.Timer(Tick,MyWCFSharedObject,_interval,Timeout.Infinite)在我的情况下...如果可以,我希望Tick方法中对MyWCFSharedObject所做的所有更改都将在Windows服务级别可见? – Francois

+0

嘀嗒 - 只是功能,你可以使它在平坦的层面上可见,你可以事件能够使其公共静态,如果你真的需要这个。 – tym32167

+0

实际上,作为示例我使用这个,https://github.com/tym32167/arma3beclient/blob/develop/src/Arma3BE.Client.Modules.BEServerModule/BEServiceLogic.cs#L108 – tym32167

1

System.Timers.Timer是要走的路,将有很少或几乎没有系统性能的影响。目前的系统可以处理数千个定时器。由于您希望定时器继续,因此不要设置AutoReset,但您需要一种方法来更改其间隔(如果这是您需要的)。

您的服务实例应该包含您的WCF通道工厂的一个实例。

为了确保同步处理,您应该实现一个Interlocked受保护的标志,如long,它可以用作繁忙指标。例如,如果等于1,则从计时器过期事件开始处理的方法将简单地返回。一旦处理完成,此时您将标志设置为零,则进一步的计时器已过时的事件将能够进入并再次启动处理。

请记住在各种服务事件中停止,重新启动和处置您的计时器,如暂停,停止,开始。

+0

有趣。当然,我的WCF通道工厂对象是在Windows服务级别定义的。我同意你的建议没有AutoReset,这是处理它的另一种方法。但我不明白为什么我需要互锁处理,因为在我的情况下不会出现并行任务? – Francois

+0

我认为在这个解决方案中你必须使用互锁,因为当你读这个标志时,另一个线程能够写入它。如果您必须在一个线程中写入内存并从另一个线程读取它,则应该使用线程安全结构。互锁是很好的线程安全读取/写入该国旗。 – tym32167

+0

好的......我刚刚认为我可能在我的Windows服务的OnStop()或OnSessionChanged()方法中有并发内存访问,例如...我已经重新阐述了有关联锁的一些黑暗点,所以我想避免他们... :) – Francois