System.Diagnostics.Stopwatch возвращает отрицательные числа в свойствах Elapsed...
Является ли обычное поведение тем, что секундомер может возвращать отрицательные значения? Пример кода, приведенный ниже, можно использовать для его воспроизведения.
while (true)
{
Stopwatch sw = new Stopwatch();
sw.Start();
sw.Stop();
if (sw.ElapsedMilliseconds < 0)
Debugger.Break();
}
Единственное место, где я могу воспроизвести отрицательные числа, - это моя виртуальная машина (размещенная Hyper-V на 8-ядерном компьютере)
Ответы
Ответ 1
Это ошибка . Похоже, что вокруг этого не слишком много внимания, поэтому я предлагаю следить за этим докладом.
непросто обходное решение означает игнорировать отрицательные значения:
long elapsedMilliseconds = Math.Max(0, stopwatch.ElapsedMilliseconds);
Ответ 2
Я декомпилировал класс Stopwatch как в .NET 2.0, так и в .NET 4.0 с помощью Reflector, а затем сравнил различия, чтобы понять, как он был исправлен. Помимо добавления нового метода Restart, это все, что я нашел для разницы:
public void Stop()
{
if (this.isRunning)
{
long num2 = GetTimestamp() - this.startTimeStamp;
this.elapsed += num2;
this.isRunning = false;
// THE NEXT 4 LINES ARE NEW IN .NET 4.0:
if (this.elapsed < 0L)
{
this.elapsed = 0L;
}
}
}
Таким образом, они устанавливаются в 0 в методе Стоп, если значение отрицательное. Есть еще ошибки IMHO:
- Что делать, если пользователь читает любое из свойств Elapsed перед остановкой секундомера? Вы все равно можете получить отрицательное значение.
- Сброс в 0 неверен. Некоторое время должно было пройти, даже если было всего несколько микросекунд!
- Он ничего не делает для обработки необычно больших положительных истекших значений, о которых я и другие сообщали.
EDIT: К сожалению, # 2 и # 3 выходят за рамки .NET Framework:
Здесь ядро проблемы: от MSDN на QueryPerformanceCounter, который является API, используемым классом секундомера:
На многопроцессорном компьютере не должно иметь значения, какой процессор называется. Тем не менее, вы можете получить разные результаты по разным процессоров из-за ошибок в базовой системе ввода/вывода (BIOS) или уровень абстракции аппаратного обеспечения (HAL). Чтобы указать сродство процессора к thread, используйте функцию SetThreadAffinityMask.
Не просто использовать секундомер .NET 4.0 и предполагать, что проблема исправлена. Это не так, и они ничего не могут с этим поделать, если вы не хотите, чтобы они гадали с вашей ниточкой. Из документации класса секундомера:
На многопроцессорном компьютере не имеет значения, какой процессор поток работает. Однако из-за ошибок в BIOS или аппаратном обеспечении Уровень абстракции (HAL), вы можете получить разные результаты синхронизации по разные процессоры. Чтобы указать сродство процессора к потоку, используйте метод ProcessThread.ProcessorAffinity.
Ответ 3
Разрешение "Закрыто как фиксированное" на Ошибка Microsoft Connect означает, что они исправили его в .NET 4. Я запустил воспроизведите код на моем рабочем столе и виртуальную машину в течение нескольких минут и не получите отрицательных значений.
Ответ 4
Единственным обходным решением, которое я нашел, чтобы получить правильное истекшее время в VM, является (VB):
Dim tstart AS DateTime = Now
...executing code...
Dim telapsed = (Now - tstart).TotalMilliseconds