2009-04-03 3 views
1

У меня есть этот код:Почему этот код выполняется быстрее, чем ожидалось?

public void replay() { 
     long previous = DateTime.Now.Ticks; 
     for (int i = 0; i < 1000; i++) { 
      Thread.Sleep(300); 
      long cur = DateTime.Now.Ticks; 
      Console.WriteLine(cur - previous); 
      previous = cur; 
     } 
    } 

который вызывается в отдельном потоке, как это:

 MethodInvoker replayer = new MethodInvoker(replay); 
     replayer.BeginInvoke(null, null); 

Однако, если я смотрю на выход, он действует странно. Он выводит i в парах. Например, он будет ждать полного ожидания, затем вывести i, затем быстро вывести следующий i, а затем снова ждать. Почему он это делает и как я могу его исправить?

Он выводит это:

3125040 
2968788 
2968788 
2968788 
3125040 
2968788 
2968788 
2968788 
3125040 
2968788 
2968788 
2968788 
3125040 

Если я увеличиваю сон более чем второй этого не происходит.

+0

Во-первых, это в режиме выпуска или отладки? Во-вторых, используйте таймер, а не только просмотр выхода на консоль - нет никакой гарантии, что консоль сразу отобразит информацию. –

+0

находится в режиме отладки – Malfist

+0

Вы уверены, что это не буферизация на консоли? – annakata

ответ

7

Изменить код, чтобы устранить задержку отображения в анализе:

public void replay() 
{   
    Thread.Sleep(5000); 
    DateTime start = DateTime.Now;  
    for (int i = 0; i < 1000; i++) 
    {    
      Console.WriteLine(string.Format("Exec:{0} - {1} ms", 
       i, DateTime.Now - start)); 
      start = DateTime.Now; 
      Thread.Sleep(300);   
    } 
} 

Глядя на ваш модифицированный выход, есть менее 5% дисперсия (15ms из 300) в задержке цикла. Это нормально, из-за неопределенностей, связанных с тем, когда ОС фактически назначает временные лимиты потоку ... (Если я правильно помню, в ОС Windows это обычно составляет только каждые 20 мс!)

Чем больше расхождение вы воспринимать в консольном выводе почти наверняка из-за отображения latencys.

-2

Ваш сон внутри петли составляет всего 300 мс, что не очень долго. Ваша заявка будет сделать следующее:

  • Sleep 5 секунд
  • печати 0
  • Сон 300мс
  • печать 1
  • Сон 300мс
  • печать 2

и т.д.

+0

Но это не так, и в этом проблема. – Malfist

5

Невозможно воспроизвести. Интересно, это что-то локальное для вашей машины; буферизация, возможно.

+0

Невозможно воспроизвести здесь. – LukeH

+0

так же. поднять диспетчер задач и посмотреть ваши процессы. Я подозреваю, что что-то ест циклы. –

+0

предложите OP записать вывод на что-то еще - словарь возможно - для двойной проверки – annakata

2

Я не могу воспроизвести это, но вы можете рассмотреть таймер. Это было бы более надежно.

public class Counter 
{ 
    private readonly TimeSpan initialDelay, incrementDelay; 
    private readonly int maxCount; 
    private Timer timer; 
    private int count; 

    public Counter(TimeSpan initialDelay, TimeSpan incrementDelay, int maxCount) 
    { 
     this.maxCount = maxCount; 
     this.initialDelay = initialDelay; 
     this.incrementDelay = incrementDelay; 
    } 

    public void Start(Action<int> tickBehavior) 
    { 
     if (timer != null) 
     { 
      Timer temp = timer; 
      timer = null; 
      temp.Dispose(); 
     } 
     timer = new Timer(() => 
      { 
       tickBehavior(count++); 
       if (count > maxCount) timer.Dispose(); 
      }, null, initialDelay, incrementDelay); 
    } 
} 

Использование:

Counter counter = new Counter(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(.3), 1000); 
counter.Start((count) => Console.WriteLine(count);); 

EDIT

Я использую System.Threading.Timer, но Counter может быть легко модифицирован для использования System.Timers.Timer или System.Windows.Forms.Timer в зависимости от ваших потребностей. См. this link for a description о том, когда использовать таймеры.

+0

+1 этот кусок кода - самая крутая вещь, которую я видел всю неделю :) –