2011-04-07 104 views
2

我使用Threading.Timer,如:Threading.Timer麻煩

new System.Threading.Timer(
      new System.Threading.TimerCallback(x=> 
       file.Write(DateTime.Now.ToString()) 
      ), null, 0, 600000); 

而且,例如,它開始於11:00:00,然後我得到的文件:

11:00 :00
11時10分〇〇秒
11時二十零分00秒
...
12點10分〇〇秒
12時19分59秒
12時29分59秒

爲什麼?從某個時候開始做這樣的事情? 我試過其他計時器,如Timers.Timer和winforms Timer,情況也是如此。 令人沮喪。

編輯:解決方案與精確定位器發佈在線程中,沒有幫助。 怎麼樣的win32多媒體計時器,它可以幫助嗎?

+0

看看這個看看http://stackoverflow.com/questions/897108/how-reliable-are-net-timers和這個http://stackoverflow.com/questions/5015255/reliable-alternative-to-timer- in-net-framework有幫助。 – gideon 2011-04-07 07:33:52

+0

另請參閱:[爲什麼.NET定時器限制爲15毫秒分辨率?](http://stackoverflow.com/questions/3744032/why-are-net-timers-limited-to-15-ms-resolution) – 2011-04-07 08:01:41

回答

3

因爲定時器機制並不理想,每次都需要部分時間file.Write(DateTime.Now.ToString()被執行,因此在適當的時候你有一秒的延遲,試着把它留給一個小時,我想你有3個秒鐘的延遲即可。

我不知道,每當System.Threading.Timer可以通過跟蹤執行時間彌補這一點,ü應該檢查選項手動

乘坐看看System.Timers.Timer類也

也試試用這個

class Timer 
{ 
    private Stopwatch sw; 
    private Thread executor; 
    private long interval; 

    public void Start(int intervalInMilliseconds) 
    { 
     interval = intervalInMilliseconds; 
     sw = new Stopwatch(); 
     executor = new Thread(Run); 
     executor.Start(); 
    } 

    public void Run() 
    { 
     while (true) 
     { 
      sw.Start(); 
      Execute(); 
      sw.Stop(); 
      Thread.Sleep((int)(interval - sw.ElapsedMilliseconds)); 
      sw.Reset(); 
     } 
    } 


    public void Execute() 
    { 
     // Do your code here 
    } 

} 
+0

是的。我延遲了15秒,然後我走了一天。我如何使它正常工作?沒有人得到這種情況? – 2011-04-07 07:18:35

+0

@Jack:現在工作正常。詳情請參閱我的回答。切換到不同的計時器實現(有3個由.NET Framework提供)不會解決這個問題。它在Windows中發生在較低級別。沒有人在這裏和那裏考慮幾毫秒的問題。 – 2011-04-07 07:46:15

+0

>雖然(真),但不是最好的解決方案,我認爲 – 2011-04-07 07:53:36

0

是的,計時器可能會被其他重要任務所佔用。在任何地方都不能保證定時器會按照您設定的時間間隔精確地執行。這只是一個近似的時間間隔,因爲Windows是一個多任務操作系統。如果計算機忙於做其他事情,它將無法立即處理您的計時器消息。所以這些消息被放入一個隊列中,這可以讓它們被推遲,直到它可以這樣做。

這就是爲什麼你應該總是檢查一個等於或大於的時間值。它保證減去時間將永不會過去,但不能保證更多時間不會過去。其他的定時器實現沒有什麼不同。

documentation的用於由Windows API提供的計時器進入更詳細地:

一個應用程序使用定時器在規定的時間已經過去之後,以調度的窗口的事件。每當定時器的指定時間間隔(或超時值)過去時,系統都會通知與定時器關聯的窗口。由於定時器的精度取決於系統時鐘速率以及應用程序從消息隊列中檢索消息的頻率,因此超時值僅爲近似值。

Windows根本沒有提供這種精確的定時機制。在100個案例中有99個,這根本不相關。對於100分之一的情況,您需要一個實時操作系統。

+0

好的。那麼哪裏沒有圖書館,哪些可以幫助我證明情況?這將爲我留下時間& – 2011-04-07 07:48:09

+0

@Jack:你已經在使用可以檢查你的時間了。它被稱爲計時器。問題在於不能保證精確到毫秒。應該預料到一些「漂移」。您顯示的數據最多顯示*一秒鐘的差異。真正的差別可能要小得多,你的代碼只是四捨五入到最接近的整數。 – 2011-04-07 07:53:01

+0

對不起。我只是想在適當的時候寫入文件。我不能這樣做?:( – 2011-04-07 07:55:59

0

這裏比較精確的定時器爲您提供:

class AccurateTimer 
{ 
    private TimerCallback _Callback; 
    private TimeSpan _Period; 
    private bool _IsWorking = true; 

    public void Stop() 
    { 
     _IsWorking = false; 
    } 

    public AccurateTimer(TimerCallback callback, int period) 
    { 
     _Period = TimeSpan.FromMilliseconds(period); 
     _Callback = callback; 

     new Thread(ThreadMethod).Start(); 
    } 

    private void ThreadMethod() 
    { 
     while (_IsWorking) 
     { 
      var start = DateTime.Now; 
      _Callback.BeginInvoke(null, null, null); 
      Thread.Sleep(_Period - (DateTime.Now - start)); 
     } 
    } 
} 

用法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var timer = new AccurateTimer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), 3000); 
     Console.ReadKey(); 
     timer.Stop(); 
    } 
} 

輸出:

11:44:46.987 
11:44:49.985 
11:44:52.985 
11:44:55.985 
11:44:58.985 
11:45:01.985 

System.Threading.Timer:

class Program 
{ 
    static void Main(string[] args) 
    { 
     new System.Threading.Timer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), null, 0, 3000); 
     Console.ReadKey(); 
    } 
} 

輸出:

11:50:22.042 
11:50:25.040 
11:50:28.051 
11:50:31.065 
11:50:34.073 
11:50:37.083 
+0

這兩個定時器之間的準確度沒有任何實際差別 – 2011-04-07 07:59:35

+0

這個例子中的第二個定時器的週期是〜3010ms,而不是3000ms,100次啓動後的錯誤將是1秒 – bniwredyc 2011-04-07 08:08:24

+0

它也會失敗。 ..( – 2011-04-08 04:07:47

0

如果你願意犧牲一些CPU時間,可以使用多媒體計時器(檢查this出來,我作爲我自己的組件的基礎樣本C#實現)。

與任何其他.NET定時器或自定義解決方案(通常都必須依賴默認的15.625 ms Windows計時器)不同,它的實際準確度高達1 ms。注意事項:(1)我只能在同一AppDomain中成功創建最多兩個此計時器的實例 - 有更多的實例,其中一些實例根本沒有引發滴答事件(或稍後)和(2)監視增加的CPU負載,並決定額外的準確性是否值得。