C #, для циклов и теста скорости & # 8230; Точно такой же цикл быстрее второй раз?

StackOverflow https://stackoverflow.com/questions/303343

Вопрос

public Int64 ReturnDifferenceA()
{
  User[] arrayList;
  Int64 firstTicks;
  IList<User> userList;
  Int64 secondTicks;
  System.Diagnostics.Stopwatch watch;

  userList = Enumerable
              .Range(0, 1000)
              .Select(currentItem => new User()).ToList();

  arrayList = userList.ToArray();

  watch = new Stopwatch();
  watch.Start();

  for (Int32 loopCounter = 0; loopCounter < arrayList.Count(); loopCounter++)
  {
     DoThings(arrayList[loopCounter]);
  }

  watch.Stop();
  firstTicks = watch.ElapsedTicks;

  watch.Reset();
  watch.Start();
  for (Int32 loopCounter = 0; loopCounter < arrayList.Count(); loopCounter++)
  {
     DoThings(arrayList[loopCounter]);
  }
  watch.Stop();
  secondTicks = watch.ElapsedTicks;

  return firstTicks - secondTicks;
}

Как видите, это действительно просто. Создайте список пользователей, принудительно создайте массив, запустите наблюдение, переберите список и вызовите метод, остановите наблюдение. Повторение. Завершите работу, вернув разницу между первым и вторым прогоном.

Теперь я звоню с этими:

differenceList = Enumerable
                 .Range(0, 50)
                 .Select(currentItem => ReturnDifferenceA()).ToList();
average = differenceList.Average();

differenceListA = Enumerable
                  .Range(0, 50)
                  .Select(currentItem => ReturnDifferenceA()).ToList();
averageA = differenceListA.Average();

differenceListB = Enumerable
                  .Range(0, 50)
                  .Select(currentItem => ReturnDifferenceA()).ToList();
averageB = differenceListB.Average();

Теперь самое интересное то, что все средние значения положительны на относительно большое количество, в пределах от 150 000 до 300 000 тиков.

Чего я не понимаю, так это того, что я иду по одному и тому же списку тем же способом, тем же методом, и все же есть такая разница. Есть ли какое-то кэширование?

Еще одна интересная вещь: если я перебираю список ДО первой секции секундомера, средние значения составляют около 5 тысяч или около того.

Это было полезно?

Решение

Кстати, использование IEnumerable.Count () в массиве в сотни раз медленнее, чем в Array.Length ... Хотя это не отвечает на вопрос вообще.

Другие советы

Вы работаете на языке высокого уровня со средой выполнения, в которой выполняется много операций кэширования и оптимизации производительности, это часто встречается. Иногда это называется прогревом виртуальной машины или прогревом сервера (когда это производственное приложение).

Если что-то будет выполняться неоднократно, вы будете часто замечать, что первый раз имеет большее измеренное время выполнения, а остальное должно выровняться до меньшего количества.

Я делаю это в коде MATLAB и вижу, что в первый раз, когда я запускаю цикл тестирования, это занимает пять секунд, а последующие - пятую секунды. Это огромная разница, потому что это интерпретируемый язык, который требует определенной формы компиляции, но на самом деле это не влияет на вашу производительность, потому что подавляющее большинство будет «второй раз» в любом производственном приложении.

Вполне возможно, что DoThings () не JIT-компилируется в нативный код, пока он не вызывается в первый раз.

Потому что .NET, как и платформа Java, является средой JIT. Весь высокоуровневый код .NET компилируется в байт-код промежуточного языка Microsoft.

Чтобы запустить вашу программу, этот байт-код необходимо скомпилировать / перевести на собственный машинный код. Однако скомпилированные запрограммированные файлы .NET хранятся не в собственном машинном коде, а в байт-коде промежуточной виртуальной машины.

Первый запуск - это JIT-компиляция, поэтому это заняло дополнительное время. Последующие запуски больше не нуждаются в JIT-компиляции, но собственный код извлекается из JIT-кэша, поэтому он должен быть быстрее.

Поддерживали ли вы свое приложение без остановки при последующих запусках? Тогда вторая причина также связана с ВМ. (ВМ: 1 = виртуальная машина; ВМ: 2 = виртуальная память). Все современные обобщенные операционные системы запускают свои процессы в виртуальной памяти, которая представляет собой карту реальной памяти, что позволяет операционной системе управлять и оптимизировать использование системных ресурсов. Менее используемые процессы часто удаляются в дисковый кэш, чтобы другие процессы могли оптимально использовать ресурсы.

Ваш процесс не находился в виртуальной памяти с первого раза, поэтому он должен быть перенесен в память. Поскольку впоследствии ваш процесс был одним из самых последних использовавшихся в верхнем списке (то есть в нижней части наименее последнего использованного списка), он еще не был удален в дисковый кеш.

Кроме того, ОС распределяет ресурсы по мере необходимости. Таким образом, в первом раунде вашему процессу пришлось пройти через все усилия, направленные на то, чтобы раздвинуть конверт с ОС, чтобы расширить границы своих ресурсов.

Виртуальная машина позволяет .NET и Java абстрагировать большинство функций программирования в уровень, независимый от машины, разделяя и, следовательно, оставляя небольшую путаницу, с которой приходится сталкиваться машинно-зависимым программистам. Даже несмотря на то, что Microsoft Windows работает на довольно унифицированном оборудовании-потомке x86, различия между версиями ОС и моделями процессоров достаточно достаточны, чтобы гарантировать абстрагированную виртуальную машину, чтобы предоставить программистам и пользователям .NET согласованное представление.

Вы говорите, что не можете сделать это 3 раза, 2 и 3 раза относительно близки. Мне кажется, что это только первый раз, когда все идет медленно.

Я подозреваю, что функция, которую вы вызываете, не работает точно по времени до первого запуска. Что вы можете попробовать, так это запустить его один раз, затем остановить и запустить снова. Без изменений кода компиляция Just-In-Time из предыдущего запуска все равно должна быть в порядке, а любые оставшиеся оптимизации - это фактические эффекты кэширования в работе.

Оставьте на минутку вопрос о разогреве виртуальной машины или машины, о кэшировании, JIT-оптимизации: что еще делает ваш компьютер? Какие-нибудь системные сервисы 3e42 и вещи из панели задач захватывают какой-то процессор? Может быть, ваш клиент Steam решил проверить наличие обновлений, или IE нужно было сделать что-то ужасно важное, или ваша антивирусная программа помешала?

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

Но тогда что я знаю? - возможно, ваш метод измерения также управляется средой выполнения .net (или какой-либо другой) и учитывает только «виртуальные циклы» времени выполнения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top