답변:
두 System.Timers.Timer
및 System.Threading.Timer
서비스에 대해 작동합니다.
당신이 피하려는 타이머는 System.Web.UI.Timer
및 System.Windows.Forms.Timer
ASP 애플리케이션과 윈폼에 대한 각각있는. 이를 사용하면 서비스가 빌드중인 애플리케이션 유형에 실제로 필요하지 않은 추가 어셈블리를로드하게됩니다.
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 페이지에서 가져 왔습니다.
이를 위해 서비스를 사용하지 마십시오. 일반 응용 프로그램을 만들고이를 실행할 예약 된 작업을 만듭니다.
이것은 일반적으로 유지되는 모범 사례입니다. Jon Galloway는 저에게 동의합니다. 아니면 그 반대 일 수도 있습니다. 어느 쪽이든간에 타이머에서 실행되는 간헐적 작업을 수행하기 위해 Windows 서비스를 만드는 것은 모범 사례가 아닙니다.
"타이머를 실행하는 Windows 서비스를 작성하는 경우 솔루션을 다시 평가해야합니다."
–Jon Galloway, ASP.NET MVC 커뮤니티 프로그램 관리자, 작성자, 파트 타임 슈퍼 히어로
둘 중 하나가 정상적으로 작동합니다. 실제로 System.Threading.Timer는 System.Timers.Timer를 내부적으로 사용합니다.
그렇긴하지만 System.Timers.Timer를 오용하기 쉽습니다. Timer 객체를 변수의 어딘가에 저장하지 않으면 가비지 수집 될 수 있습니다. 이 경우 타이머가 더 이상 실행되지 않습니다. Dispose 메서드를 호출하여 타이머를 중지하거나 약간 더 멋진 래퍼 인 System.Threading.Timer 클래스를 사용합니다.
지금까지 어떤 문제를 보셨습니까?
System.Timers.Timer
예외를 처리하지 않기 때문에 액세스 권한이없는 이유를 더 잘 제공한다고 생각 합니다.
다른 접근 방식을 고려하는 것이 가장 좋은 이전 의견에 동의합니다. 내 제안은 콘솔 응용 프로그램을 작성하고 Windows 스케줄러를 사용하는 것입니다.
이것은 :
이 스레드가 조금 오래되었지만 내가 가진 특정 시나리오에 유용하다는 것을 알고 System.Threading.Timer
있으며 좋은 접근 방식이 될 수있는 또 다른 이유가 있음을 주목할 가치가 있다고 생각했습니다 . 시간이 오래 걸릴 수있는 작업을 주기적으로 실행해야하고 작업간에 전체 대기 기간이 사용되는지 확인하거나 이전 작업이 완료되기 전에 작업을 다시 실행하지 않으려는 경우 작업이 타이머 기간보다 오래 걸립니다. 다음을 사용할 수 있습니다.
using System;
using System.ServiceProcess;
using System.Threading;
public partial class TimerExampleService : ServiceBase
{
private AutoResetEvent AutoEventInstance { get; set; }
private StatusChecker StatusCheckerInstance { get; set; }
private Timer StateTimer { get; set; }
public int TimerInterval { get; set; }
public CaseIndexingService()
{
InitializeComponent();
TimerInterval = 300000;
}
protected override void OnStart(string[] args)
{
AutoEventInstance = new AutoResetEvent(false);
StatusCheckerInstance = new StatusChecker();
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate =
new TimerCallback(StatusCheckerInstance.CheckStatus);
// Create a timer that signals the delegate to invoke
// 1.CheckStatus immediately,
// 2.Wait until the job is finished,
// 3.then wait 5 minutes before executing again.
// 4.Repeat from point 2.
Console.WriteLine("{0} Creating timer.\n",
DateTime.Now.ToString("h:mm:ss.fff"));
//Start Immediately but don't run again.
StateTimer = new Timer(timerDelegate, AutoEventInstance, 0, Timeout.Infinite);
while (StateTimer != null)
{
//Wait until the job is done
AutoEventInstance.WaitOne();
//Wait for 5 minutes before starting the job again.
StateTimer.Change(TimerInterval, Timeout.Infinite);
}
//If the Job somehow takes longer than 5 minutes to complete then it wont matter because we will always wait another 5 minutes before running again.
}
protected override void OnStop()
{
StateTimer.Dispose();
}
}
class StatusChecker
{
public StatusChecker()
{
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Start Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
//This job takes time to run. For example purposes, I put a delay in here.
int milliseconds = 5000;
Thread.Sleep(milliseconds);
//Job is now done running and the timer can now be reset to wait for the next interval
Console.WriteLine("{0} Done Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
autoEvent.Set();
}
}