2013-07-02 3 views
7

Обычно, когда у меня есть большой цикл я помещал сообщения, чтобы сообщить мне, в какой части процесса моя программа, например:информативный «если» заявление в «для» петли

for(i = 0; i < large_n; i++) { 
    if(i % (large_n)/1000 == 0) { 
     printf("We are at %ld \n", i); 
    } 
    // Do some other stuff 
} 

мне было интересно, если это слишком сильно увеличивает производительность (априори), и если это так, если есть более разумная альтернатива. Спасибо заранее.

+2

в любом случае в конце вы его не снимаете? – Alexis

+1

Почему вы делаете '/ 1000'? Я бы сказал, что для этого достаточно 'i% large_n'. –

+3

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

ответ

5

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

int T = ...; // times to check the condition, make sure large_n % T == 0 
for(int t = 0; t < T; ++t) 
{ 
    for(int i = large_n/T * t; i < large_n/T * (t+1); ++i) 
    { 
    // other stuff 
    } 
    printf("We are at %ld \n", large_n/T * (t+1)); 
} 
+1

Спасибо за ваш ответ! – Bunder

3

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

if ((i & 0xFF) == 0) { 
    /* this gets printed every 256 iterations */ 
    ... 
} 

или

if ((i & 0xFFFF) == 0) { 
    /* this gets printed every 65536 iterations */ 
    ... 
} 
+0

Это printf, который использует CPU, а не if – LtWorf

+0

@LtWorf не всегда. Если вы кодируете очень сложный цикл, который выполняет некоторую простую арифметику и работает невероятно быстро, то процент времени, затраченного на выражение 'if', имеет значение. Несомненно, это редкий случай, но когда это имеет значение, это может помочь. В то время как printf() занимает много времени, он становится ничтожно малым, если в цикле его зовут экономно, поэтому цель вызова 'if' в первую очередь просто печатать. Поэтому, хотя ваше утверждение, как правило, правильное, было бы ошибкой сделать пустой звонок без знания того, что содержит цикл. –

4

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

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

#define DEBUG 

for(i = 0; i < large_n; i++) 
{ 
    #ifdef DEBUG 
     if(i % (large_n)/1000 == 0) 
     { 
      printf("We are at %ld \n", i); 
     } 
    #endif 
} 

Что касается стоимости производительности, включая эту Debug выводит все время, она полностью будет зависеть от системы, вы работаете, эффективность любой «печать» который вы используете для вывода данных, проверки/вы выполняете и, конечно, как часто вы пытаетесь выполнить вывод.

+0

+1 для упоминания DEBUG, OP, вероятно, сочтет полезным, что его можно определить с помощью флага компилятора '-DDEBUG = 1', с большой отладкой помощников. – Nobilis

0

Поставив инструкцию печати внутри цикла for, вы жертвуете некоторой производительностью.

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

Вы можете увидеть разницу в производительности между этими двумя петлями:

int i; 
printf("Start Loop A\n"); 
for(i = 0; i < 100000; i++) { 
    printf("%d ", i); 
} 
printf("Done with Loop A\n"); 

printf("Start Loop B\n"); 
for(i = 0; i < 100000; i++) { 
    // Do Nothing 
} 
printf("Done with Loop B\n"); 

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

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

Ой, забыл закончить свой ответ.

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

Например, если вы подсчитывая, как в моем примере кода, вы могли бы напечатать только каждый 100-ый номер с помощью %:

int i; 
for(i = 0; i < 100000; i++) { 
    if(i%100 == 0) 
     printf("%d", i); 
} 

Это позволит сократить количество системных вызовов от ~ 100000 до ~ 1000 , что, в свою очередь, увеличило бы производительность цикла.

+1

Это в значительной степени то, что я делаю. Вопрос скорее в том, что оператор «if» вредит производительности. – Bunder

+0

Извините, я неправильно понял вопрос. –

0

Проблема в работе ввода-вывода printf занимает много времени, чем вычисляет процессор. вы можете сократить время, если можете добавить их все и окончательно распечатать.

0

нотация:

Tp = total time spent executing the progress statements. 
Tn = total time spent doing the other normal stuff. 
>> = Much greater than 

Если производительность ваши основные критерии, вы хотите Tn >> Tp. Это настоятельно указывает на то, что код должен быть профилирован, чтобы вы могли выбрать подходящие значения. Подпрограмма 'printf()' считается медленной (намного медленнее, чем%) и является процедурой блокировки (то есть поток, который ее вызывает, может ожидать ожидания ресурса, используемого им).

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

id = progressRegister (<some predefined type of progress update mechanism>); 
for(i = 0; i < large_n; i++) { 
    progressUpdate (id, <string>, i, large_n); 
    // Do some other stuff 
} 
progressUnregister(id); 

Да, есть некоторые накладные расходы в вызове подпрограммы «progressUpdate()» на каждой итерации, но опять же, до тех пор, как Tn >> Tp, как правило, не так уж важно.

Надеюсь, это поможет.

Смежные вопросы