问题描述
我改变我的for循环递增使用 ++我
我++ ,并开始思考,而不是,是这真的有必要了吗?当然,今天的编译器自己做这种优化。
I was changing my for loop to increment using ++i
instead of i++
and got to thinking, is this really necessary anymore? Surely today's compilers do this optimization on their own.
在这篇文章中,,从1997年迈克尔·李进入其他优化,如内联,循环展开,循环堵塞,循环反转,强度降低,等等。这些还有用吗?
In this article, http://leto.net/docs/C-optimization.php, from 1997 Michael Lee goes into other optimizations such as inlining, loop unrolling, loop jamming, loop inversion, strength reduction, and many others. Are these still relevant?
我们应该做一个什么水平低code优化这么做的,我们可以放心地忽略了什么优化?
编辑:这有什么好做premature优化。 以优化的决定已经作出。现在的问题是什么,是做最有效的方法。
This has nothing to do with premature optimization. The decision to optimize has already been made. Now the question is what is the most effective way to do it.
故事:有一次,我回顾了规定要求的一个规范:程序员由一个人留下,而不是乘以2转变
anecdote: I once reviewed a requirements spec that stated: "The programmer shall left shift by one instead of multiplying by 2".
推荐答案
如果没有成本的优化,做到这一点。当写code, ++我
是一样容易写的我++
,所以preFER前者。有没有成本的。
If there is no cost to the optimization, do it. When writing the code, ++i
is just as easy to write as i++
, so prefer the former. There is no cost to it.
在另一方面,回去并使这种变化的之后的需要时间,而且它很可能不会作出明显的区别,所以你可能不应该理会它。
On the other hand, going back and making this change afterwards takes time, and it most likely won't make a noticeable difference, so you probably shouldn't bother with it.
但是,是的,它可以有所作为。关于内置类型,可能不会,但对于复杂的类时,编译器是不太可能能够优化它扔掉。这样做的原因是,增量操作没有不再是一种固有的操作,内置于编译器,但在该类中定义的功能。编译器可以是能够优化它像任何其他的功能,但它不能在一般情况下,假定$ P $对增量可以用来代替后递增。这两个函数可能会做完全不同的事情。
But yes, it can make a difference. On built-in types, probably not, but for complex classes, the compiler is unlikely to be able to optimize it away. The reason for this is that the increment operation no is no longer an intrinsic operation, built into the compiler, but a function defined in the class. The compiler may be able to optimize it like any other function, but it can not, in general, assume that pre-increment can be used instead of post-increment. The two functions may do entirely different things.
所以,确定哪些优化可以由编译器完成后,考虑是否有足够的信息来执行它。在这种情况下,编译器不知道后增量和$ P $对增量执行相同的修改的对象,所以不能假设可以与其他被替换。但是,你有这方面的知识,这样你就可以放心地进行优化。
So when determining which optimizations can be done by the compiler, consider whether it has enough information to perform it. In this case, the compiler doesn't know that post-increment and pre-increment perform the same modifications to the object, so it can not assume that one can be replaced with the other. But you have this knowledge, so you can safely perform the optimization.
许多你提到通常可以由编译器非常高效地完成别人:
内联可以由编译器来完成,而且它通常它比你更好。它所需要知道的是功能的比例有多大包括函数调用了头,它是如何经常叫什么名字?那个叫往往可能是一个大的函数不应该被内联,因为你最终复制了很多code,导致一个更大的可执行文件,多指令高速缓存未命中。内联始终是一个权衡,并经常,编译器在权衡所有的因素比你更好。
Many of the others you mention can usually be done very efficiently by the compiler:Inlining can be done by the compiler, and it's usually better at it than you. All it needs to know is how large a proportion of the function consists of function call over head, and how often is it called? A big function that is called often probably shouldn't be inlined, because you end up copying a lot of code, resulting in a larger executable, and more instruction cache misses. Inlining is always a tradeoff, and often, the compiler is better at weighing all the factors than you.
循环展开是一个纯粹的机械操作,编译器可以做到这一点很容易。也是一样的强度降低。交换内环和外环是棘手,因为编译器必须证明改变顺序遍历不会影响结果,这是困难的自动执行。因此,这里是一个优化,你应该做你自己。
Loop unrolling is a purely mechanic operation, and the compiler can do that easily. Same goes for strength reduction. Swapping inner and outer loops is trickier, because the compiler has to prove that the changed order of traversal won't affect the result, which is difficult to do automatically. So here is an optimization you should do yourself.
但即使是在那些简单的编译器是能够做到的,你有时有资料编译器不。如果你知道一个函数将是极其通常被称为,即使它只是从一个地方叫,它可能是值得检查编译器是否自动内联它,如果不是做手工。
But even in the simple ones that the compiler is able to do, you sometimes have information your compiler doesn't. If you know that a function is going to be called extremely often, even if it's only called from one place, it may be worth checking whether the compiler automatically inlines it, and do it manually if not.
有时你可能知道更多关于循环比编译器,以及(例如,迭代的次数永远是4的倍数,所以你可以放心地展开它的4倍)。编译器可能没有这些信息,所以如果它是内联循环,那就要插入一个收尾,以保证最后的几个迭代得到正确执行。
Sometimes you may know more about a loop than the compiler as well (for example, that the number of iterations will always be a multiple of 4, so you can safely unroll it 4 times). The compiler may not have this information, so if it were to inline the loop, it would have to insert an epilog to ensure that the last few iterations get performed correctly.
所以,这样的小规模的优化仍然可以是必要的,如果1)你实际需要的性能,以及2)你有信息的编译器不会。
So such "small-scale" optimizations can still be necessary, if 1) you actually need the performance, and 2) you have information that the compiler doesn't.
您不能超越纯粹的机械优化编译器。但是,你可以作出假设,编译器不能和的是的是,当你能够优化比编译器更好。
You can't outperform the compiler on purely mechanical optimizations. But you may be able to make assumptions that the compiler can't, and that is when you're able to optimize better than the compiler.
这篇关于如果我们仍然是优化"在小"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!