2015-08-03 42 views
1

我試着用Rx擴展解決方案回答another question。當我做出解決方案時,我發現有些奇怪。反應式擴展序列化任務每個都可以取消

static Random rand = new Random(); 

static void Main(string[] args) { 
    //var obs = Observable.Interval(TimeSpan.FromMilliseconds(250)).Do<long>(i => 
    var obs = Observable.Interval(TimeSpan.FromMilliseconds(25)).Do<long>(i => 
    { 
     CancellationTokenSource source = new CancellationTokenSource(25); 
     //CancellationTokenSource source = new CancellationTokenSource(250); 
     ReadNext(source.Token, i); 
    }).Publish(); 
    var disp = obs.Connect(); 
    Console.ReadKey(); 
    disp.Dispose(); 
    Console.ReadKey(); 
} 

static private void ReadNext(CancellationToken token, long actual) { 
    int i = rand.Next(4); 
    Stopwatch watch = new Stopwatch(); 
    watch.Start(); 
    for(int j = 0; j < i; j++) { 
     //Thread.Sleep(100); 
     Thread.Sleep(10); 
     if(token.IsCancellationRequested) { 
      Console.WriteLine(string.Format("method cancelled. cycles: {0}, should be 3. Now should be last (2): {1}", i, j)); 
      return; 
     } 
    } 
    Console.WriteLine(string.Format("method done in {0} cycles. Preserved index: {1}. Elapsed time: {2}", i, actual, watch.ElapsedMilliseconds)); 
    watch.Stop(); 
} 

取消超時有問題。不知何故,當第三個週期發生時(我們已經等待了大約30毫秒),ReadNext不會每次都取消。

退房打印輸出:

method done in 1 cycles. Preserved index: 7. Elapsed time: 9 
method done in 1 cycles. Preserved index: 8. Elapsed time: 9 
method done in 0 cycles. Preserved index: 9. Elapsed time: 0 
method cancelled. cycles: 3, should be 3. Now should be last (2): 2 
method done in 1 cycles. Preserved index: 11. Elapsed time: 9 
method done in 2 cycles. Preserved index: 12. Elapsed time: 19 
method done in 2 cycles. Preserved index: 13. Elapsed time: 19 
method done in 0 cycles. Preserved index: 14. Elapsed time: 0 
method done in 2 cycles. Preserved index: 15. Elapsed time: 19 
method done in 0 cycles. Preserved index: 16. Elapsed time: 0 
method done in 1 cycles. Preserved index: 17. Elapsed time: 9 
method cancelled. cycles: 3, should be 3. Now should be last (2): 2 
method done in 1 cycles. Preserved index: 19. Elapsed time: 9 
method done in 3 cycles. Preserved index: 20. Elapsed time: 29 <- bug. 
method done in 2 cycles. Preserved index: 21. Elapsed time: 19 
method done in 1 cycles. Preserved index: 22. Elapsed time: 9 
method done in 1 cycles. Preserved index: 23. Elapsed time: 9 
method done in 2 cycles. Preserved index: 24. Elapsed time: 19 
method done in 2 cycles. Preserved index: 25. Elapsed time: 19 
method done in 2 cycles. Preserved index: 26. Elapsed time: 19 
method done in 1 cycles. Preserved index: 27. Elapsed time: 10 
method done in 1 cycles. Preserved index: 28. Elapsed time: 9 
method done in 3 cycles. Preserved index: 29. Elapsed time: 29 <- bug. 
method done in 1 cycles. Preserved index: 30. Elapsed time: 9 

我一定要聽一些其他的調度,可以肯定的是,經過25毫秒取消標記是肯定取消,或其他東西造成的錯誤?

編輯

如果我升級由一個睡覺的順序(檢查註釋代碼段),它的工作原理。問題是Thread.Sleep不夠精確。

+1

我認爲問題是'Thread.Sleep'不夠精確。看到這[問題](http://stackoverflow.com/questions/1303667/how-accurate-is-thread-sleeptimespan) – juharr

+0

我正在檢查增加睡眠的訂單。我可以通過某種方式觀察或更改'Thread.sleep',所以等待與取消相同的線程? – ntohl

+0

Thread.sleep沒有足夠精確的確認。它使用哪個線程/調度程序? – ntohl

回答

2

Windows不是實時操作系統。一般來說,系統定時器以60Hz運行,這意味着它們只能精確到16.7ms。事實上,有更多的線程比運行它們的物理內核要多得多,而且你不能期望編寫具有精確時序的代碼,而不必知道自己在做什麼。因此,無論何時寫定時器代碼,只要假設你啓動的任何定時器都會以+/- 16ms的精度觸發。

相關問題