Альтернатива DotNet (MONO- http://www.go-mono.com/mono-downloads/download.html) правильно обрабатывает условие короткого таймера (время срабатывания до ~ 12 мс). Тем не менее, DotNet, похоже, занимает больше времени, чем ожидалось, и "промахивается". Итак, какое поведение правильное? Правильно ли моно отслеживает срабатывание своего события? Может, он подставляет свой номер из-за неправильного секундомера? или в DotNet есть «ленивый» таймер событий? С моим тестированием ясно, что это не основная проблема Windows.
.NET 200ms+ Interval minimum
Mono 12ms+ Interval minimum
Этот запрос аналогичен следующему: Таймер занимает на 10 мс больше, чем интервал .
Однако рассмотрим код:
В .NET пропущенные события будут медленно расти:
Total Runtime/Interval - Actual Events = Missed Events
Код:
class Program
{
const int Interval = 60; //ms Event fireing
Stopwatch TotalRunTime = new Stopwatch();//Full runtime.
Stopwatch Calctime = new Stopwatch(); //Used to load up the Event to 66 percent
System.Timers.Timer TIMER; //Fireing Event handler.
int TotalCycles = 0; //Number of times the event is fired.
int Calcs_per_cycle = 100; // Number of calcs per Event.
static void Main(string[] args)
{
Program P = new Program();
P.MainLoop();
}
void MainLoop()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
TIMER = new Timers.Timer();
TIMER.Interval = Interval;
TIMER.Elapsed += new ElapsedEventHandler(MS_Calc);
TIMER.AutoReset = true;
TIMER.Enabled = true; //Start Event Timer
TotalRunTime.Start(); //Start Total Time Stopwatch;
while (true)
{
Thread.Sleep(Interval * 5);
Console.Clear();
PrintAtPos(2, "Missed Events " + (((TotalRunTime.ElapsedMilliseconds / Interval) - TotalCycles).ToString()));
}
}
public void MS_Calc(object source, System.Timers.ElapsedEventArgs E)// public void MS_Calc(object source, ElapsedEventArgs E)
{
TotalCycles++;
Calctime.Start();
for (int i = 0; i < Calcs_per_cycle; i++)
{
int A = 2;
int B = 2;
int c = A + B;
}
PrintAtPos(1, "Garbge Collections G1: " + GC.CollectionCount(0) + " G2: " + GC.CollectionCount(1) + " G3: " + GC.CollectionCount(2) + " ");
Calctime.Stop();
if (Interval * 0.667 > Calctime.ElapsedMilliseconds) //only fill the even timer 2/3s
//full to make sure we finish before the next event
{
Calcs_per_cycle = (int)(Calcs_per_cycle * 1.035);
}
Calctime.Reset();
PrintAtPos(0, "Calc Time : " + (DateTime.Now - E.SignalTime).Milliseconds + " Calcs/Cycle: " + Calcs_per_cycle);
}
private static void PrintAtPos(int Vertical_Pos, string Entry)
{
Console.SetCursorPosition(0, Vertical_Pos);
Console.Write(Entry);
}
}
TotalCycles
(на самом деле оно записывается только одним потоком), и результаты будут такими же, если вы сделаете этоvolatile
и используетеInterlocked.Increment
. - person Mike Zboray   schedule 20.12.2012calcs_per_cycle
ограничен, чтобы он не увеличивался больше, чем 2/3 интервала (честно говоря, я не вижу смысла в этом цикле). Все это в значительной степени не имеет значения, потому что суть проблемы заключается в пропущенных событиях, а не в 0 GC или продолжительности цикла вращения. - person Mike Zboray   schedule 20.12.2012totalCycles++
для того же эффекта (илиThread.Sleep((int)(Interval * 0.667));
для имитации тяжелых вычислений). - person Alexei Levenkov   schedule 20.12.2012