正如Knuth所说,
我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源.
这是Stack Overflow常常出现的问题,例如"哪个是最有效的循环机制","SQL优化技术?"等问题.(等等).这些优化提示问题的标准答案是分析您的代码并首先查看它是否是一个问题,如果不是,那么您的新技术就不再需要了.
我的问题是,如果某种技术不同但不是特别模糊或混淆,那真的可以被认为是过早的优化吗?
这是Randall Hyde的一篇名为"过早优化的谬误"的相关文章.
如今优化似乎是一种迷失的艺术.所有程序员都没有从代码中挤出每一盎司的效率吗?经常在雪地里行走五英里的时候这样做?
本着回归丢失的艺术的精神,您知道的简单(或复杂)变化以优化C#/ .NET代码的一些提示是什么?因为它是如此广泛,取决于一个人想要完成什么,它有助于提供你的提示的背景.例如:
StringBuilder.请参阅底部的链接以了解相关信息.string.Compare两个字符串比较,而不是做这样的事情string1.ToLower() == string2.ToLower()到目前为止,普遍的共识似乎是衡量关键.这种方式忽略了这一点:测量不会告诉你什么是错的,或者如果遇到瓶颈会怎么做.我遇到了字符串连接瓶颈一次,不知道该怎么办,所以这些提示很有用.
我甚至发布这个问题的意思是为了解决常见的瓶颈问题,以及在遇到这些问题之前如何避免它们.它甚至不一定是任何人应该盲目遵循的即插即用代码,而是更多关于获得对性能应该被考虑的理解,至少在某种程度上,并且需要注意一些常见的陷阱.
我可以看到,知道为什么提示有用以及应该应用的位置可能会有用.对于StringBuilder小费,我找到了很久以前在Jon Skeet网站上做过的帮助.
我一直听说C++比Java更有效(这就是大多数游戏都是用C++开发的原因).
我写了一个小算法来解决Java和C++中的"八皇后谜题",使用完全相同的算法,然后开始提高数字或方块.当到达20*20甚至22*22的检查板时,看起来Java更有效(3秒对C++的66秒).
我不知道为什么,但我从C++开始,所以我可能会犯一些巨大的性能错误,所以我很乐意接受任何可以帮助我理解正在发生的事情的信息.
下面是我在Java中使用的代码:
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
public class HuitDames {
/**
* La liste des coordnnées des dames.
*/
private static List<Point> positions = new ArrayList<>();
/**
* Largeur de la grille.
*/
private static final int LARGEUR_GRILLE = 22;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
int i = 1;
placerDame(i);
for (Point point : positions) {
System.out.println("(" + point.x + "; " + point.y + ")"); …Run Code Online (Sandbox Code Playgroud) 迭代比递归更高效,对吧?那么为什么有些人认为递归比迭代更好(用他们的话来说更优雅)?我真的不明白为什么像Haskell这样的语言不允许迭代并鼓励递归?鼓励表现不佳的东西是不是很荒谬(当更高性能的选项即递归可用时也是如此)?请详细说明一下.谢谢.
通过指针进行内存访问比通过数组进行内存访问更有效.我正在学习C,上面的内容在K&R中有说明.他们特别说
通过数组下标可以实现的任何操作也可以使用指针来完成.指针版本通常会更快
我使用visual C++解组了以下代码.(我是一个686处理器.我已禁用所有优化.)
int a[10], *p = a, temp;
void foo()
{
temp = a[0];
temp = *p;
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,我看到通过指针的内存访问需要通过数组对内存访问所采用的两条指令.以下是相应的代码.
; 5 : temp = a[0];
mov eax, DWORD PTR _a
mov DWORD PTR _temp, eax
; 6 : temp = *p;
mov eax, DWORD PTR _p
mov ecx, DWORD PTR [eax]
mov DWORD PTR _temp, ecx
Run Code Online (Sandbox Code Playgroud)
请帮我理解.我在这里失踪了什么?
正如许多答案和评论所指出的那样,我使用了编译时常量作为数组索引,从而使得通过数组访问变得更容易.下面是汇编代码,其中变量作为索引.我现在有相同数量的指令通过指针和数组进行访问.我更广泛的问题仍然很好.通过指针进行内存访问并不会使其本身更有效.
; 7 : temp = a[i];
mov eax, DWORD PTR _i
mov ecx, DWORD PTR _a[eax*4]
mov DWORD PTR _temp, …Run Code Online (Sandbox Code Playgroud) 我有一种心理tic,这让我不愿意在C和C++等低级语言中使用大型库(如GLib或Boost).在我看来,我认为:
嗯,这个图书馆有数千个小时的时间,而且它是由那些比我更了解语言的人创造的.他们的作者和粉丝说这些库是快速可靠的,而且功能看起来非常有用,它肯定会阻止我(严重地)重新发明轮子.
该死的,我永远不会使用该库中的所有功能.它太大了,多年来可能会变得臃肿; 这是我的程序需要拖延的另一个球和链.
该托沃兹咆哮(争议虽然它是)不完全把我的心脏放心无论是.
我的想法有什么依据,还是我只是不合理和/或无知?即使我只使用大型库的一个或两个功能,通过链接到该库我会产生运行时性能开销吗?
我确信它还取决于具体的库是什么,但我通常很想知道大型库是否会在技术层面上固有地引入低效率.
当我没有技术知识知道我是否正确的时候,我已经厌倦了对此的痴迷,嘀咕和担心.
请把我从痛苦中解救出来!
如果某个东西正在使单线程程序占用,比如10倍,那么就可以在其上运行一个分析器.您也可以通过"暂停"按钮暂停它,您将看到它正在做什么.
即使它比它应该慢了10%,如果你停止它多次,不久你会看到它反复做不必要的事情.通常问题是在堆栈中间某处不是真正需要的函数调用.这不能衡量问题,但确实找到了.
编辑:反对意见主要假设您只采取1个样本.如果你是认真的,请采取10.任何一行代码,导致一定比例的浪费,如40%,将平均出现在该部分样本的堆栈上.瓶颈(单线程代码)无法隐藏它.
编辑:为了表明我的意思,许多反对意见的形式是"没有足够的样本,所以你看到的可能完全是虚假的" - 关于机会的模糊观点.但是,如果任何可识别的描述,不仅仅是在常规或常规活动中,在30%的时间内有效,那么在任何给定样本上看到它的概率是30%.
然后假设只采集了10个样本.在10个样本中看到问题的次数遵循二项分布,并且看到它0次的概率是.028.看到它1次的概率是.121.2次,概率为.233,而3次则为.267,之后下降.由于看到它少于两次的概率是.028 + .121 = .139,这意味着看到它两次或更多次的概率是1 - .139 = .861.一般规则是,如果您看到可以修复两个或更多样本的内容,则值得修复.
在这种情况下,在10个样本中看到它的机会是86%.如果你是14%没有看到它的人,那就去做更多的样品.(如果样本数量增加到20,那么两次或多次观察的几率会增加到99%以上.)所以它没有经过精确测量,但已经准确找到了,重要的是要了解它它可能很容易成为分析器无法实际找到的东西,例如涉及数据状态的东西,而不是程序计数器.
我正在研究对性能至关重要的科学代码.该代码的初始版本已经编写和测试,现在,有了分析器,现在是时候从热点开始剃须周期了.
众所周知,编译器现在可以更有效地处理一些优化,例如循环展开,而不是手工编程的程序员.哪些技术还值得?显然,我会通过一个分析器来运行我尝试的所有内容,但是如果有传统的智慧关于什么往往有效,哪些无效,这将为我节省大量时间.
我知道优化非常依赖于编译器和体系结构.我正在使用针对Core 2 Duo的英特尔C++编译器,但我也对gcc或"任何现代编译器"的效果感兴趣.
以下是我正在考虑的一些具体想法:
std::priority_queue),其操作占用了大量的总时间.这是值得研究的事情,还是STL实施可能是最快的?std::vector需要大小未知但上限相当小的s,用静态分配的数组替换它们是否有利可图?最后,将某些类型的答案扼杀在萌芽状态:
我记得在某处可以真正优化和加速代码的某些部分,程序员用汇编语言编写该部分.我的问题是 -
我正在努力理解这个概念,非常感谢任何帮助或链接.
更新:根据dbemerlin的要求改写第3点 - 因为您可能能够编写比编译器生成的更有效的汇编代码,但除非您是汇编专家,否则您的代码运行速度会慢,因为编译器通常会比大多数人更好地优化代码.