通常,当我有一个大的 for 循环时,我会放置消息以通知我我的程序处于进程的哪个部分,例如:
for(i = 0; i < large_n; i++) {
if( i % (large_n)/1000 == 0) {
printf("We are at %ld \n", i);
}
// Do some other stuff
}
我想知道这是否会对性能(先验)造成太大的伤害,如果有更聪明的选择,是否会出现这种情况。提前致谢。
通常,当我有一个大的 for 循环时,我会放置消息以通知我我的程序处于进程的哪个部分,例如:
for(i = 0; i < large_n; i++) {
if( i % (large_n)/1000 == 0) {
printf("We are at %ld \n", i);
}
// Do some other stuff
}
我想知道这是否会对性能(先验)造成太大的伤害,如果有更聪明的选择,是否会出现这种情况。提前致谢。
也许你可以拆分大循环以便有时只检查条件,但我不知道这是否真的会节省时间,这更多地取决于你的“其他东西”。
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));
}
无论你的循环中有什么,我都不会留下像 in 这样的语句,除非它对应用程序/用户来说是必不可少的,出于同样的原因,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
}
关于始终包含这些调试输出的性能成本,这将完全取决于您正在运行的系统、您用于输出数据的任何“打印”语句的效率、您正在执行的检查当然,还有你尝试执行输出的频率。
您的 mod 测试可能不会影响性能,但如果您想要一个非常快速的测试并且您已准备好进行 2 的倍数,那么请考虑进行数学and
测试:
if ( ( i & 0xFF ) == 0 ) {
/* this gets printed every 256 iterations */
...
}
或者
if ( ( i & 0xFFFF ) == 0 ) {
/* this gets printed every 65536 iterations */
...
}
通过在 for 循环中放置 print 语句,您会牺牲一些性能。
因为程序需要在每次打印消息时执行系统调用以将输出写入屏幕,所以它占用了程序本身的 CPU 时间。
您可以看到这两个循环之间的性能差异:
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,从而提高循环的性能。
问题是 IO 操作printf
花费的时间比处理器计算的要长。如果您可以将它们全部添加并最终打印,则可以减少时间。
符号:
Tp = total time spent executing the progress statements.
Tn = total time spent doing the other normal stuff.
>> = Much greater than
如果性能是您的主要标准,您需要 Tn >> Tp。这强烈建议应该对代码进行分析,以便您可以选择适当的值。例程 'printf()' 被认为是一个慢例程(比 % 慢得多)并且是一个阻塞例程(也就是说,调用它的线程可能会等待它使用的资源)。
就个人而言,我喜欢抽象出进度指示器。它可以是日志机制、printf、进度框……哎呀,它可能正在更新由另一个线程/任务/进程读取的结构。
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,它通常并不那么重要。
希望这可以帮助。