У меня есть метод c#, который периодически вызывается камерой. Событие вызова, как известно, очень точное. Камера работает на частоте 2500 Гц, поэтому этот метод следует вызывать каждые 400 микросекунд.
Вот упрощенная версия метода:
// Main class
private static List<double> T_Copy = new List<double>();
private static List<double> T_Call = new List<double>();
private static Stopwatch SW_Copy = new Stopwatch();
private static Stopwatch SW_Call = new Stopwatch();
void PeriodicalCalled()
{
// (...) some other stuff inside a "if" condition which is not called for the sake of this test
if (MyDLL.Flag)
{
// Elapsed time between method calls
SW_Call.Stop();
T_Call.Add(SW_Call.Elapsed.TotalMilliseconds);
SW_Call.Restart();
// Elapsed time to perform a copy
SW_Copy.Restart();
Buffer = new byte[4, 2560 * 3];
SDK.GetBuffer(Buffer);
MyDLL.CopyBuffer(Buffer);
SW_Copy.Stop();
T_Copy.Add(SW_Copy.Elapsed.TotalMilliseconds);
}
// This Flag is set once CopyBuffer has reached the end of its buffer size
if (!MyDLL.Flag && T_Call.Count > 0)
{
string[] SaveText = new string[T_Call.Count];
for (int i = 0; i < T_Call.Count; ++i) SaveText[i] = "Call; " + T_Call[i] + "; Copy; " + T_Copy[i];
File.WriteAllLines("timeTest.txt", SaveText);
T_Call.Clear();
T_Copy.Clear();
}
}
// Enables test
void SetFlag()
{
MyDLL.Flag = true;
}
// MyDLL class
public static bool MyFlag = false;
private const int SIZE = 20000;
private static byte[][,] MyBuffer = new byte[SIZE][,];
private static int MyBufferIndex = 0;
public static void CopyBuffer(byte[,] Buffer)
{
MyBuffer[MyBufferIndex] = Buffer;
MyBufferIndex++;
if (MyBufferIndex >= SIZE)
{
MyFlag = false;
// Do work with filled MyBuffer
}
}
Тест запускается путем вызова метода SetFlag (). Для каждого события, запускаемого SDK, я создаю новый пустой массив byte [,], который будет заполняться методом SDK.GetBuffer (). Затем я отправляю массив в MyDLL, который будет ссылаться на этот массив при следующем индексе MyBuffer.
Так что, как вы можете видеть, каждая итерация этого кода выполняет точно такую же работу. Однако при просмотре файла timeTest.txt время, затрачиваемое на каждую итерацию, не одинаково.
Скажем, итерации 19900/20000 верны (значения T_Copy меньше 50 микросекунд, а значения T_Call близки к 400 микросекундам (+ - 5 микросекунд)).
Оставшиеся 100 итераций действительно занимают гораздо больше времени, до 10 миллисекунд, и случайным образом распределяются между 20000 итерациями. Всякий раз, когда это происходит, PeriodicalCalled () блокируется до тех пор, пока копирование буфера не будет завершено, и на следующей итерации T_Call будет содержать значение, немного превышающее 10 миллисекунд.
Вызов 0,4432 Копировать 0,0199
Звонок 0,3823 Копия 12,3993
Звонок 12,506 Копия 0,0094
Звонок 0,3878 Копия 0,0069
Звонок 0,3698 Копия 0,0069
- Этот код запускается в отдельном потоке с Priority.Highest
- Я посмотрел на использование памяти / процессора, и все выглядит нормально.
- Я деактивировал несколько Windows сервисов (Защитник, Брандмауэр, Обновление), но ничего не изменил.
У вас есть идеи, почему производительность внезапно меняется?
Спасибо,
Редактировать:
Спасибо @germi за поиск причины проблемы. Я изменил следующий код:
// Enables test
void SetFlag()
{
GC.TryStartNoGCRegion(SIZE * 4 * 2560 * 3);
MyDLL.Flag = true;
}
public static void CopyBuffer(byte[,] Buffer)
{
MyBuffer[MyBufferIndex] = Buffer;
MyBufferIndex++;
if (MyBufferIndex >= SIZE)
{
MyFlag = false;
GC.EndNoGCRegion();
// Do work with filled MyBuffer
}
}
Единственное ограничение, которое это накладывает, состоит в том, что максимальный РАЗМЕР составляет около 8000 кадров, что по-прежнему составляет около 250 МБ памяти.