2015-08-03 2 views
1

Я попытался ответить another question с расширением Rx. Пока я принимал решение, я нашел что-то странное.Реактивное расширение сериализованной задачи с каждой отменой

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 миллисекунд маркер отмены, безусловно, отменен, или что-то другое вызывает ошибку?

EDIT

Если я Upgrade Сны заказ на один (чеком прокомментировал код выше), он работает. Проблема в том, что 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 не является оперативной системой. В общем, системные таймеры работают на частоте 60 Гц, а это значит, что они только с точностью до 16,7 мс. Добавьте в то, что есть много гораздо больше потоков, чем есть физические ядра для их запуска, и вы просто не можете рассчитывать написать код, который имеет точное время, не зная, что вы делаете.

Итак, при написании кода таймера просто предположите, что любые таймеры, которые вы запускаете, будут стрелять с точностью +/- 16 мс.

Смежные вопросы