2014-04-22 2 views
2

문제가 있습니다. 사실 저는 프레임 워크의 Timer와 Programe에서 다른 타이머를 사용해야합니다 .Net은 내가 원하는 것을하지 않습니다. 그래서 나는 내 자신의 타이머를 만들기로 결정했지만 타이머는 너무 많은 CPU를 사용합니다. 내 코드 :과도한 CPU 사용량

using System; 
using System.Threading; 

namespace XXXXXXX.Common.Types 
{ 
public delegate void TimerFinishedEventHandler(object sender, EventArgs e); 

class Timer 
{ 
    #region Attributes 
    private long m_InitialTickCount; 
    private long m_Interval; 
    private Thread m_Thread; 
    private bool m_Enabled; 
    #endregion 

    #region Events 
    public event TimerFinishedEventHandler Finished; 
    #endregion 

    #region Constructors 
    public Timer(long interval, TimerFinishedEventHandler e) 
    { 
     Finished += e; 
     m_Interval = interval; 
     Start(m_Interval); 
    } 
    #endregion 

    #region Public methods 
    /// <summary> 
    /// Start the timer thread. 
    /// </summary> 
    public void Start(long interval) 
    { 
     m_Interval = interval; 
     m_Enabled = true; 
     m_InitialTickCount = Environment.TickCount; 

     if (m_Thread == null) 
     { 
      m_Thread = new Thread(Check); 
      m_Thread.Start(); 
     } 
    } 

    /// <summary> 
    /// Stop the Timer. 
    /// </summary> 
    public void Stop() 
    { 
     m_Enabled = false; 
    } 

    /// <summary> 
    /// Restart the Timer. 
    /// </summary> 
    public void Restart() 
    { 
     m_InitialTickCount = Environment.TickCount; 
    } 
    #endregion 

    #region Private methods 
    /// <summary> 
    /// Check if the timer is finished or not. 
    /// </summary> 
    private void Check() 
    { 
     while (true) 
     { 
      if (!m_Enabled) 
       return; 

      if (Environment.TickCount > m_InitialTickCount + m_Interval) 
      { 
       OnFinished(EventArgs.Empty); 
       return; 
      } 
     } 
    } 

    /// <summary> 
    /// Called when the Timer is Finished. 
    /// </summary> 
    /// <param name="e">Event</param> 
    protected virtual void OnFinished(EventArgs e) 
    { 
     if (Finished != null) 
      Finished(this, e); 
    } 
    #endregion 
} 
} 

해결책이있는 사람이 있습니까? 내 프로그램을 시작하면 2 또는 3 개의 타이머가 만들어지고 다른 스레드가 실행되고 100 % CPU를 사용하게됩니다.

+1

코드가 누락 되었습니까? –

+2

자신 만의 타이머를 작성해야한다고 결정하기 전에 무엇을하고 싶은지 알려주시겠습니까? 제공된 타이머가 원하는대로 작동 할 가능성이 큽니다. –

+0

@AMADANONInc. 죄송합니다. 편집했습니다. – Veriditas

답변

2

여러 타이머를 사용할 수있는 이유는 없습니다. 나는 타이머의 수백을 가진 프로그램을 가지고 있으며, 언제든지 그들 중 소수는 실제로 일을 할 수 있습니다. 타이머의 요점은 정기적 인 작업을 예약하고 작업이 실제로 처리되는 경우를 제외하고 CPU 리소스를 소비하지 않도록 허용한다는 것입니다. 즉, 분당 한 번 틱하는 타이머를 설정하면 해당 타이머는 스레드를 차지하지 않으며 타이머 핸들 및 콜백 주소의 토큰 양을 초과하는 메모리를 소비하지 않으며 소비하지 않습니다 모든 CPU 자원. 타이머가 분당 한 번 "틱"할 때만 코드를 실행하도록 할당 된 스레드입니다. 일반적으로 이미 존재하는 풀 스레드이므로 스레드 시작 시간은 무시할 수 있습니다.

타이머를 사용하는 것은 매우 쉽습니다. 타이머를 실행하는 방법을 만들고 타이머를 실행하도록 예약합니다. 예를 들면 : 당신은 다른 타이머 시저를 30 초마다 틱 실행 다른 타이머를 가질 수

System.Threading.Timer myTimer = 
    new System.Threading.Timer(MyTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); 

void MyTimerProc(object state) 
{ 
    // do something here 
} 

는 :

System.Threading.Timer myOtherTimer = 
    new System.Threading.Timer(MyOtherTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); 

void MyOtherTimerProc(object state) 
{ 
    // do something else here 
} 

타이머는 서로 간섭하지 않습니다. 물론 타이머 procs의 코드가 공유 데이터를 수정하면 (예 : 두 procs 모두 목록이나 사전을 업데이트하려고 시도합니다), 공유 데이터에 대한 액세스를 동기화하거나 동시 데이터 구조를 사용해야합니다.

타이머 proc의 처리가 타이머 기간보다 오래 걸리는 경우 재진입 문제가 발생합니다. MyTimerProc의 처리가 60 초보다 오래 걸리면 다른 타이머 틱이 나타날 수 있으며 이제는 타이머 프로 시저를 실행하는 두 개의 스레드가 있습니다. 귀하의 코드가 그것을 처리하도록 설정되어 있지 않으면 많은 종류의 문제가 발생할 수 있습니다. 일반적으로 타이머를 원샷으로 만들고 각 처리주기가 끝날 때 타이머를 다시 시작하여 문제를 해결할 수 있습니다. 여기에 Stack Overflow에서이를 수행하는 예제가 있습니다.

System.Timers.TimerSystem.Threading.Timer 주위의 구성 요소 래퍼입니다. 그것이 "고성능 스레딩을 위해 최적화 된"또는 그와 같은 아이디어는 어리 석다. System.Timers.Timer은 익숙한 이벤트 지향 인터페이스를 제공하며 System.Threading.Timer처럼 명시 적으로 Invoke을 사용하지 않고 특정 스레드에서 이벤트를 발생시킬 수있는 SynchronizingObject을 제공합니다. 일반적으로 UI 애플리케이션에서만 유용합니다.

System.Timers.Timer은 버그라고 생각되는 하나의 추악한 "특징"을 가지고 있습니다. 예외를 과장합니다. the documentation가 말하기를 : 이전 .NET Framework 버전 2.0에서

을하고, 타이머 구성 요소 어획량과는 경과 이벤트에 대한 이벤트 핸들러에 의해 throw 모든 예외를 억제한다.

.NET 4.5에는 여전히 문제가 있습니다. 이벤트 핸들러는 예외가 발생

private static void OnTimedEvent(object source, ElapsedEventArgs e) 
{ 
    // do stuff here 
} 

경우, 다시 예외를 찌그러 트려 타이머 코드에 전파하고 그것에 대해 이야기하지 않습니다 : 문제는 당신이 당신의 Elapsed 이벤트가있는 경우이다. 실제로 타이머는 다음을 수행합니다.

try 
{ 
    OnTimedEvent(source, args); 
} 
catch 
{ 
    // Squash those pesky exceptions. Who needs them? 
} 

예외가 발생했는지 결코 알지 못하기 때문에 버그 소유자입니다. 따라서 프로그램이 작동하지 않고 이유를 파악할 수 없습니다. 이러한 이유 때문에 System.Timers.Timer을 사용하지 말 것을 강력히 권합니다. 대신 System.Threading.Timer을 사용하십시오. 결국, System.Timers.Timer이 구축 된 기반입니다.

+0

고마워. System.Threading.Timers를 사용하려고 시도 할 것이고 코드를 보여 드리겠습니다. – Veriditas

1

질문에 직접 답하려면 CPU 사용량이 너무 많은 이유는 긴 while 루프를 사용하여 경과 이벤트를 확인하는 것입니다. 이것은 스핀 락 (매우 비효율적 인 이유는 스레드가 고정 루프에서 잠금 변수를 검사하여 "회전"하는 세마포어를 구현하기 때문입니다.)라고도합니다.

private void Check() 
{ 
    while (true) 
    { 
     if (!m_Enabled) 
      return; 

     Thread.Sleep(10); //10 millisecond resolution for this timer 
     if (Environment.TickCount > m_InitialTickCount + m_Interval) 
     { 
      OnFinished(EventArgs.Empty); 
      return; 
     } 
    } 
} 

해상도는 당신이 잠을 시간에 따라 달라집니다 대신 꽉 루프의

, 당신은 차단하고 잠시 동안 실행하는 다른 뭔가를 허용해야합니다. 즉, 제공된 타이머는 항상 2 System.Threading.Timers를 사용하여 sufficent 일해야합니다. 저는 개인적으로 System.Threading.Timer와 System.Timers.Timer의 여러 가지를 아무 문제없이 사용했습니다.

물론 이러한 모든 타이머를 사용하면 공유 리소스에 액세스 할 때 조심해야합니다 (다른 스레드를 차단하는 기존 타이머가 무엇을 의미하는지). 교착 상태는 멀티 스레딩에서 매우 실제적인 시나리오이지만 타이머와 관련이 없습니다.

+0

고맙습니다. 당신의 매우 발달 된 대답. 나는 Thread.Sleep을 시도하고 완벽합니다. 사실 두 번째 정밀도는 필요 없지만 1 분만 필요합니다. Thread.Sleep (50000)을 추가했습니다. 그리고 그것은 완벽합니다! – Veriditas

+0

다행히 도울 수있었습니다! – BradleyDotNET

+1

Aarrghh! 슬립() 폴링 루프. NOOOOO! –

0

@ Jim Mischel. 내 웹 사이트에 연결하는 내 수업에서

, 확인 datas : 다른 클래스에서

 #region Attributes 
     private static Timer m_TimerNextCheck; 
     #endregion 

     #region Méthodes publiques 
     public static void StartCheck() 
     { 
      Thread licenceThread = new Thread(Checking); 
      licenceThread.Start(); 
     } 
     #endregion 

     #region Méthodes privées 
     private static void Checking() 
     { 
      //connect to the website 

      try 
      { 
       HttpWebResponse httpWebResponse = (HttpWebResponse) request.GetResponse(); 

       StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.Default); 

       string response = streamReader.ReadToEnd(); 

       httpWebResponse.Close(); 

       if (//Some code) 
       { 
        //Some code 
       } 
       else 
       { 

        if (m_TimerNextCheck == null) 
         m_TimerNextCheck = new Timer(TimerNextCheckFinished, null, 300000, Timeout.Infinite); 
        else 
         m_TimerNextCheck.Change(300000, Timeout.Infinite); 

       } 
      } 
      catch (WebException exception) 
      { 
       //Some code 

       if (m_TimerNextCheck == null) 
        m_TimerNextCheck = new Timer(TimerNextCheckFinished, null, 60000, Timeout.Infinite); 
       else 
        m_TimerNextCheck.Change(60000, Timeout.Infinite); 
      } 
     } 

     private static void TimerNextCheckFinished(object statusInfos) 
     { 
      Checking(); 
     } 
     #endregion 

:

#region Attributs 
    private Thread m_ConnectionThread; 
    private Timer m_TimerConnectionThread; 
    #endregion 

    #region Méthodes publiques 
    public void Launch() 
    { 
     m_ConnectionThread = new Thread(Connect); 
     m_ConnectionThread.Start(); 
    } 

    public void GetNextMeal() 
    { 
     //Some code 

     if (//Some code) 
     { 
      //Some code 

      if (m_TimerConnectionThread == null) 
       m_TimerConnectionThread = new Timer(TimerConnectionThreadFinished, null, 
        (int)TimeSpan.FromHours(difference.Hour).TotalMilliseconds + 
        (int)TimeSpan.FromMinutes(difference.Minute).TotalMilliseconds, Timeout.Infinite); 
      else 
       m_TimerConnectionThread.Change((int)TimeSpan.FromHours(difference.Hour).TotalMilliseconds + 
        (int)TimeSpan.FromMinutes(difference.Minute).TotalMilliseconds, Timeout.Infinite); 
     } 
     else 
     { 
      //Some code 
     } 
    } 

    public void TryReconnect(int minute) 
    { 
     //Some code 

     if (m_TimerConnectionThread == null) 
      m_TimerConnectionThread = new Timer(TimerConnectionThreadFinished, null, (int)TimeSpan.FromMinutes(minute).TotalMilliseconds, 
       Timeout.Infinite); 
     else 
      m_TimerConnectionThread.Change((int)TimeSpan.FromMinutes(minute).TotalMilliseconds, Timeout.Infinite); 

     //Some code 
    } 

    //Some code 
    #endregion 

    #region Méthodes privées 
    private void Connect() 
    { 
     if (m_TimerConnectionThread != null) 
      m_TimerConnectionThread.Change(Timeout.Infinite, Timeout.Infinite); 

     //Some code 
    } 

    //Some code 

    private void TimerConnectionThreadFinished(object stateInfo) 
    { 
     Connect(); 
    } 
    #endregion 

그리고 좋은 작품!