Проблема в расчете времени, необходимого для выполнения функции - PullRequest
1 голос
/ 19 июля 2011

Я пытаюсь найти время, необходимое для запуска функции. Я делаю это так:

SomeFunc(input) {
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    //some operation on input          

    stopWatch.Stop();

    long timeTaken = stopWatch.ElapsedMilliseconds;
}

Теперь "некоторая операция по вводу", как упоминалось в комментариях, занимает значительное время, исходя из ввода в SomeFunc.

Проблема в том, что когда я звоню SomeFunc несколько раз с основного, я правильно получаю timeTaken только в первый раз, а в остальное время он назначается 0. Есть ли проблемы с приведенным выше кодом?

EDIT: Существует пользовательский интерфейс с несколькими текстовыми полями, и при нажатии кнопки он делегируется SomeFunc. SomeFunc выполняет некоторые вычисления на основе входных данных (из текстовых полей) и отображает результат в пользовательском интерфейсе. Мне не разрешено делиться кодом в «какой-то операции по вводу», так как я подписал NDA. Однако я могу ответить на ваши вопросы о том, чего я пытаюсь достичь там. Пожалуйста, помогите.

РЕДАКТИРОВАТЬ 2: Поскольку кажется, что я получаю странное значение, когда функция вызывается в первый раз, и, как упоминал @Mike Bantegui, должна происходить оптимизация JIT, единственное решение, о котором я могу думать сейчас (чтобы не получить ноль как время выполнения) это для отображения времени в нано секундах. Как можно отобразить время в нано секундах в C #?

Ответы [ 3 ]

2 голосов
/ 19 июля 2011

Ну, вы нигде не выводите эти данные. В идеале вы бы сделали это как-то так.

void SomeFunc(input)
{
  Do sstuff
}

main()
{
  List<long> results = new List<long>();
  Stopwatch sw = new Stopwatch();
  for(int i = 0; i < MAX_TRIES; i++)
  {
     sw.Start();
     SomeFunc(arg);
     sw.Stop();
     results.Add(sw.ElapsedMilliseconds);
     sw.Reset();
  }

  //Perform analyses and results
}
2 голосов
/ 19 июля 2011

На самом деле вы получаете неправильное время при первом запуске и правильное время до остальных. Вы не можете ретранслировать только по первому звонку, чтобы измерить время.Однако кажется, что операция слишком быстрая, и поэтому вы получите 0 результаты.Чтобы правильно измерить тест, вызовите функцию 1000 раз, например, чтобы увидеть среднее время затрат:

Stopwatch watch = StopWatch.StartNew();
for (int index = 0; index < 1000; index++)
{
    SomeFunc(input);
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);

Редактировать:

Как можноотобразить время в нано секундах

Вы можете получить watch.ElapsedTicks и затем преобразовать его в наносекунды: (watch.ElapsedTicks / Stopwatch.Frequency) * 1000000000

1 голос
/ 19 июля 2011

В качестве простого примера рассмотрим следующий (надуманный) пример:

double Mean(List<double> items)
{
    double mu = 0;
    foreach (double val in items)
        mu += val;
    return mu / items.Length;
}

Мы можем рассчитать время так:

void DoTimings(int n)
{
    Stopwatch sw = new Stopwatch();
    int time = 0;
    double dummy = 0;

    for (int i = 0; i < n; i++)
    {
        List<double> items = new List<double>();
        // populate items with random numbers, excluded for brevity

        sw.Start();
        dummy += Mean(items);
        sw.Stop();
        time += sw.ElapsedMilliseconds;
    }

    Console.WriteLine(dummy);
    Console.WriteLine(time / n);
}

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

void DoTimings(int n)
{
    Stopwatch sw = new Stopwatch();
    int time = 0;
    double dummy = 0;

    List<double> items = new List<double>(); // Reuse same list
    // populate items with random numbers, excluded for brevity

    sw.Start();
    for (int i = 0; i < n; i++)
    {
        dummy += Mean(items);
        time += sw.ElapsedMilliseconds;
    }
    sw.Stop();

    Console.WriteLine(dummy);
    Console.WriteLine(time / n);
}

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

Однако, прежде чем делать что-либо из этого, я бы сделал расчет «разминки» перед раздачей:

// Or something smaller, just enough to let the compiler JIT
double dummy = 0;
for (int i = 0; i < 10000; i++) 
    dummy += Mean(data);
Console.WriteLine(dummy);

// Now do the actual timing

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

Со всем этим сказано, я бы сказал, тамэто одно очень большое предостережение во всем этом: Очень трудно правильно рассчитать время, необходимое для запуска чего-либо.Замечательно хотеть делать профилирование, но вы должны сделать некоторое исследование SO и посмотреть, что другие люди сделали, чтобы сделать это правильно.Очень легко написать процедуру, которая иногда что-то плохо, но очень трудно сделать это правильно.

...