Время выполнения цикла - PullRequest
       5

Время выполнения цикла

0 голосов
/ 09 сентября 2010

У нас возникла проблема с производительностью в цикле C # while. Цикл был очень медленным, делая только один простой математический расчет. Оказывается, что parmIn может быть огромным числом от 999999999 до MaxInt. Мы не ожидали гигантского значения parmIn. Мы исправили наш код, используя другую методологию.

Цикл, закодированный для простоты ниже, сделал один математический расчет. Мне просто любопытно, каково фактическое время выполнения для одной итерации цикла while, содержащего один простой математический калькулятор?

int v1=0;

while(v1 < parmIn) {
    v1+=parmIn2;
}

Ответы [ 7 ]

9 голосов
/ 09 сентября 2010

Здесь происходит что-то еще.Следующее будет завершено в ~ 100 мс для меня.Вы говорите, что parmIn может подойти к MaxInt.Если это так, а ParmIn2> 1, вы не проверяете, переполнен ли ваш int + новый int.Если ParmIn >= MaxInt - parmIn2, ваш цикл может никогда не завершиться, поскольку он откатится к MinInt и продолжится.

static void Main(string[] args)
{
    int i = 0;

    int x = int.MaxValue - 50;

    int z = 42;

    System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
    st.Start();

    while (i < x)
    {
        i += z;
    }

    st.Stop();

    Console.WriteLine(st.Elapsed.Milliseconds.ToString());
    Console.ReadLine();

}
2 голосов
/ 09 сентября 2010

При условии оптимального компилятора, это должна быть одна операция для проверки условия while и одна операция для сложения.

1 голос
/ 09 сентября 2010

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

Однако это зависит от фактической скорости процессора и еще много чего.ровно насколько маленький.

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

В любом случае код, как показано, также страдает от:

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

Какой у вас реальный вопрос?

0 голосов
/ 09 сентября 2010

Всякий раз, когда кто-то спрашивает о том, насколько быстрыми структурами управления на любом языке вы знаете, он пытается оптимизировать не то, что нужно.Если вы обнаружите, что меняете все свои i++ на ++i или меняете все свои switch на if...else для повышения скорости, вы оптимизируете микро.А микрооптимизации почти никогда не дают вам желаемой скорости.Вместо этого, подумайте немного больше о том, что вы действительно пытаетесь сделать, и придумайте лучший способ сделать это.

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

// assuming v1, parmIn and parmIn2 are integers,
// and you want the largest number (v1) that is
// smaller than parmIn but is a multiple of parmIn2.
// AGAIN, assuming INTEGER MATH:

v1 = (parmIn/parmIn2)*parmIn2;

EDIT : я только что понял, что код, который был изначально написан, дает наименьшее число, которое являетсякратный parmIn2, который больше, чем parmIn.Итак, правильный код:

v1 = ((parmIn/parmIn2)*parmIn2)+parmIn2;

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

int v1=0;
int incrementer=parmIn2;

// keep doubling the incrementer to
// speed up the loop:
while(v1 < parmIn) {
    v1+=incrementer;
    incrementer=incrementer*2;
}
// now v1 is too big, back off
// and resume normal loop:
v1-=incrementer;
while(v1 < parmIn) {
    v1+=parmIn2;
}

Вот еще одна альтернатива, которая ускоряет цикл:

// First count at 100x speed
while(v1 < parmIn) {
    v1+=parmIn2*100;
}
// back off and count at 50x speed
v1-=parmIn2*100;
while(v1 < parmIn) {
    v1+=parmIn2*50;
}
// back off and count at 10x speed
v1-=parmIn2*50;
while(v1 < parmIn) {
    v1+=parmIn2*10;
}
// back off and count at normal speed
v1-=parmIn2*10;
while(v1 < parmIn) {
    v1+=parmIn2;
}

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

0 голосов
/ 09 сентября 2010

Если вас интересует фактическое время выполнения, почему бы не рассчитать его для себя и узнать?

int parmIn = 10 * 1000 * 1000;  // 10 million
int v1=0;

Stopwatch sw = Stopwatch.StartNew();
while(v1 < parmIn) {
    v1+=parmIn2;
}
sw.Stop();

double opsPerSec = (double)parmIn / sw.Elapsed.TotalSeconds;

И, конечно, время для одной итерации составляет 1/opsPerSec.

0 голосов
/ 09 сентября 2010

Цикл while - это пара инструкций и одна инструкция для математической операции. Вы действительно смотрите на минимальное время выполнения для одной итерации. это огромное количество итераций, которые вы делаете, убивает вас.

Обратите внимание, что подобный замкнутый цикл влияет и на другие вещи, так как он блокирует один процессор и блокирует поток пользовательского интерфейса (если он работает на нем). Таким образом, он не только медленный из-за количества операций, но и добавляет ощутимое влияние перфорирования из-за того, что вся машина выглядит безразличной.

0 голосов
/ 09 сентября 2010

Это зависит от процессора, который вы используете, и вычислений, которые он выполняет.(Например, даже на некоторых современных архитектурах добавление может занять только один тактовый цикл, но деление может занять много тактовых циклов. Существует сравнение, чтобы определить, должен ли цикл продолжаться, что, вероятно, будет около одного тактового цикла,и затем переход обратно к началу цикла, который может занять любое количество циклов в зависимости от размера конвейера и прогноза перехода)

ИМХО лучший способ узнать больше - поместить интересующий вас кодочень большой цикл (миллионы итераций), время цикла и деление на количество итераций - это даст вам представление о том, сколько времени занимает каждая итерация цикла.(на вашем ПК).Вы можете попробовать различные операции и немного узнать о том, как работает ваш компьютер.Я предпочитаю этот «практический» подход (по крайней мере, для начала), потому что вы можете узнать гораздо больше из физической попытки, чем просто попросить кого-то сказать вам ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...