返回首页

介绍
我爱的。NET Framework,C#和智能感知,但很多人还是说,它比C慢指出,视频游戏和"主要applicationsquot;仍用C语言编写。反对者经常点指出,如Office,Internet Explorer和Windows媒体播放器的应用程序仍然用C写的,显然是暗示,C仍是最好的选择,性能。别急,这主要是因为这些应用程序的旧比的。NET Framework本身,或者是因为。NET Framework的支持糟糕DirectShow中,或低于理想的Direct3D支持?好吧,我已经使用C#多年,很少有任何关于其性能的投诉 - 也就是说,直到我写了一个程序为Pocket PC和震惊地发现,它需要35秒启动。这篇文章中,我试图让一个公平的比较之间的C#和C(非托管),在台式机和移动的Windows CE的场景表现。在本文的第一版中,我写道大部分彗星#一中的代码,和手动移植它,线,通过的路线,到C,取代标准。NET的类STL的等值(部分代码是在其他移植方向)。因为这是劳动密集,然而,这些基准的品种和范围是有限的。此更新版本,我增加了三个额外的跨语言基准由两个不同的人写的,再加上对Hashtable中使用排序映射的基准的变化。我的主要目标是在性能上的差异来衡量的编译/ JIT和部分,是最常用的标准库。我反正C标准库在很大程度上限制我的测试,所以没有办法像XML解析或JPG加载,我们可以比较东西的速度。NET Framework的BCL可以做,但C标准库不能。不,我基准,将被限制在以下几个方面: 字符串处理:std::字符串VS System.Stringnbsp;哈希表:hash_maplt;钾,VGT; VS Dictionarylt,K,VGT; 二叉树:maplt;钾,VGT; VS SortedDictionarylt,K,VGT; 结构简单:在我的工作中,我往往最终创建小的性能的关键结构,如一个整数字段定点类型,。数学泛型:你去{A}写数学代码,使用NET泛型。你也遭受一个性能命中NBSP?;简单的算术:加和减法;乘法,除法和模由一个常数,对不同类型的数据。我也尝试一个整数的平方根的算法(和其浮点完整性,相当于)。64位整数:一些与这些漂亮的poorly.nbsp编译器的处理;文本文件扫描的速度有多快,我们可以读文本文件的行由行 ?排序的P / Invoke和(C#只)无操作方法这篇文章的更新原来的文章在Visual Studio 2008编译的代码;这些结果旁边,我加入了Visual Studio 2010中(包括NET 4中)和Mono的结果,所以你可以看到其中的差别。在VS 2010中,这是摆在首位的原因,我用VS 2008中,微软下跌支持为Windows CE。当然,我欢迎读者尝试编译的代码与其他的编译器或平台(如GCC或Windows Phone 7)。要知道,你观察到的任何差异可能会使用不同的处理器以及不同的编译器造成的。我的测试工作站的四核64位英特尔Q9500@2.83千兆赫(但所有的测试都是单线程)在Windows 7。移动设备是一个了600MHz的ARM处理器,和。NET Compact Framework 3.5的。
许多个人给了原始版本的这篇文章中quot; 1quot;投票。他们大多不愿意或无法说明为什么我应得的最低可能得分,但让我解决了一些具体的批评。衷心的感谢出去的人发现不完善的,但没有惩罚我!在C中,你没有禁用检查的迭代器:一个疏忽。我不知道检查的迭代器在发布版本中启用。原来,VC9两种不同的东西减慢你的C代码。一个被称为quot;迭代debuggingquot;(只在调试构建启用),有时可以使代码可笑缓慢;另外一个,所谓的quot;迭代checkingquot;或"检查iteratorsquot;有一个较小的效果,但在发行中启用建立默认。 (一个1选民的报告,他们在VS2010默认被禁用。)我知道的第一和第二混为一谈。对不起。这一次,他们将被禁止在每一个场景除了one.nbsp;您移植的语言之间的代码行线:这样呢?不要y'all有什么具体说吗?难道你看看代码?我选择了这样一种方式,在两种语言中的相同的方式做同样的任务,这是完全合理的C和C#的一个子集。我只收到一份具体批评,GenericSum在C语言编写的方式。我试图解释,C编译器都配备了一种叫一个quot; optimizerquot;可以执行所谓的quot; inliningquot一招,(我的图形显示)导致的基准测试结果一样好,因为他们将没有不必要的函数调用。但是,票来看,有些人不相信。所以这个时候,我已经改变了C代码来消除额外的函数调用,但我是被迫删除C测试(显示的功能是虚拟时性能会发生什么)之一。当然,还是有其他两个功能要求在那里,但我认为这是非常标准的C代码,在这一点上,和优化仍然存在。在C中,你没有启用支持SSE2或浮动"; fastquot;点模式:真。我必须承认,我的主要目标是ARM性能基准,它提供了没有神奇的编译器开关,使代码运行得更快。这一次,我会做单独的VC9测试,一次在x86的默认编译器开关,并再次与架构= sse2,浮点模型= quot; fastquot,并没有检查的迭代器,所以y'all可以看出其中的差别,和第三次x64和所有花里胡哨。我仍然认为它的合理没有SSE2的基准,因为有些旧型电脑可以不运行一个可执行文件,对SSE2的依赖(顺便说一下,我没有能够以确定时,非,SSE2的处理器停止正在生产或什么%的市场份额,SSE2的有。)不过,据我所知,所有x64系统支持SSE2(纠正我,如果我错了!)。因此,当你64建立,你可能以及启用支持SSE2。同样,如果你限制自己当前的根系统(或如果你发布你的程序单独建立旧电脑),这是一个好主意,使SSE2。您没有使用VS2010的:你给我只为1? Eww。好的,我会基准VS2010的。我将让SSE2和所有VC10测试快速浮点模型。但你是我的生日派对不请自来的。有关配置文件导引优化(PGO):好吧,我现在多达6套C基准测试结果的不同,我不知道如何将现实的"警察通例"的结果。毕竟,输入的数据是相同的在每个试验中,和一些基准是人为的。所以,"警察通例",可能无法提供相同的性能提高,在现实世界中的代码对这些基准。我有一个更现实(但封闭源代码)的C基准测试中,我可以运行,并没有"警察通例",发表评论,如果有兴趣,或者干脆上运行现有的基准自己的警察通例。比较的语言和不执行他们的图书馆:如果每个人都写自己的哈希表,列表,文件管理代码和字符串类从头开始!而且不要忘了,内存管理标准库的一部分;内存分配是禁地吗?你看,我的一些基准没有使用任何标准的库,而最让很少或根本没有分配。忽略那些使用标准库,如果他们让你出于某种原因不舒服。使用更复杂的现实生活中的算法:你要我两次在两种不同的语言写一个庞大而复杂的现实生活中的算法?当然!只要名称的算法,并告诉我,我的时间,你将支付多少....告诉你吧,我发现了一些第三方的多语文基准。他们不是超复杂,但是它没关系,如果我使用这些吗?
一些非- 1 -选民建议,应避免在彗星由于其性能较差,差的设计,以防止高性能ifstream的。给出的结果,他们显然是正确的!我对于这个基准测试添加的文件*测试(不是直接调用Win32 API,因为我喜欢可移植的代码。)
有一些其他1票的批评,我不可能使用改进的文章,例如:微软(!在公司的最高技术职务)...技术研究员说,NET是不利于系统编程:不写你的下一个操作系统在C#。这是什么都与我?过于主观:为什么,因为我承认自己喜欢彗星#?还等什么?你能说出什么特别是与我的代码错吗?在方法论上的严重问题:特别??您的文章包含了大量虚假和误导性陈述:我问你的名字之一,但你没有。一个点努力:Riiiight。你真的有一个扭曲的心灵:我试着不让它影响的结果。我想投票,虽然罗恩保罗/丹尼斯Kucinich门票。这是很知名的本地代码是更快:哦,当然,这是我错了,来衡量不同!好吧,我很抱歉,如果我的CPU背叛您的信任。但我的结果表明,C是一般的速度稍快(如果您选择优质的C库),并大大加快基于ARM。因此,我们同意与对方,你给我1反正的!此外,C赢取新的Sudoku大幅度测试,并在x64 JIT的低迷,我发现了一些新的原因。这是否意味着在C爱好者现在给我一个5和C#的爱好者,会突然切换他们的选票,以1?从微软的市场营销的东西吗?请考虑发表了许多意见和更新你的基准:请考虑了大量的更新和更新您的投票。我最喜欢的,学习C可能是一个很好的起点,然后再尝试使用它在一个基准点:我一直在C编程,因为我在1994年买下我的第一台PC。除其他事项外,我写了一个SNES模拟器和一个ARM与定制优化的绘图基元的GPS系统,在C从头开始。接下来,我想你会告诉我,我不是一个quot; realquot; C程序员,除非我写我的代码在大会...
这里是希望这段时间大约为一个较为合理的讨论。
在我开始之前,我应该指出,有没有简单的方法,与基准相匹配的垃圾收集,所以我之前,每一个C#基准的GC,和我不尝试,包括在GC时间总计。我本来希望打印出最终的总GC时间,但显然是不可能的。总GC时间没有财产或性能计数器有一个quot; instantaneousquot测量; quot;%的GC timequot,但没有明显的方式,随着时间的推移,它聚集。我可以禁用除测试地方选区,但一些GC的时间将misattributed不正确的地方。我可以添加强迫GC时间,每个测试中测得的时间,但人为地抬高C#的时间数(因为强迫根2集合浪费时间相比,quot; naturalquot; GCS)。然而,GC时间不应该的问题在这里多,因为大多数这些基准不分配大量的堆对象(涉及字符串和SortedDictionary的测试除外)NBSP。
测试场景
已经很清楚,当涉及到桌面软件,目标CPU,目标JIT(在C#)和编译器开关(三)有时会影响大的性能。所以这个新版本的文章,我将测试几个不同场景(共11个),所以你可以看到其中的差别,使编译器开关。我可以测试更多的场景,但图的是变得越来越拥挤。"X86 VC9 defaultquot;:优化版本建立默认的编译器开关,X86,VC 2008"X86 VC9 NCI的x86quot;:没有检查的迭代器,发布版本,默认的编译器开关,X86,2008年的VC"VC9的x86 SSE2 x86quot;:发布版本,没有检查的迭代器,SSE2,FP模式,全面优化,快速的x86"64 VC9 SSE2 x64quot;:发行版本,没有检查的迭代器,SSE2,快速FP模式,全面优化,64"X86 VC10支持SSE2 x64quot;:发布版本,没有检查的迭代器,SSE2,快速的FP模式,全面优化,64,VC 2010"64 VC10支持SSE2 x64quot;:发布版本,没有检查的迭代器,SSE2,快速的FP模式,全面优化,64,VC 2010"X86 Monoquot;:内置在VS2008中,用Mono运行默认的编译器开关"x86的NET3quot;:VS2008中,微软NET Framework 3.5中,X86(JIT是相同的。NET 2.0)。"64 NET3quot:VS2008,微软NET Framework 3.5中,X64(JIT是相同的。NET 2.0)。"X86 NET4quot:VS2010中,微软NET Framework 4.0中,64"64 NET4quot:VS2010中,微软NET Framework 4.0中,64。
我也基准的quot; VC9 NCI的x86quot;设置加/ Ox(完全优化),看它是否从默认/ O2(最大化速度)的显着不同。差异很小,在每一个基准,不值得包括作为一个条形图独立的酒吧。
一,两个人想知道是否单声道会更快,如果LLVM的JIT( - LLVM命令行开关)会更快。我发现了LLVM在当前版本的Windows(单声道2.10.2)没有显著差异。一些测试运行速度稍快,多数跑稍微慢一点。并有第一次运行(当JIT的发生)和后续运行之间只有小的差异,表明JIT的时间是不缺乏速度增加的原因。 - LLVM和无差异足够小,我觉得这是不值得的,包括在酒吧charts.nbsp;
我将获得的quot; realquot;在一分钟内标杆。但首先... ... ;与发行buildsnbsp调试
一些C语言开发结束分发Debug版本,以便"assertquot;语句继续工作,或使他们能​​调试生产机器,如果他们要。不幸的是,这往往杀性能,下面的图表显示
(注:我没有新文章更新这些图表我不认为新的图表会教给我们任何关于调试版本。)
{S0}
在这个图中,规模已调整,以便在x86发行建设需要一个时间单位。一些操作,最显着的功能电话和任何涉及STL中,在桌面调试慢得多构建。我怀疑";通用sumquot;是这么多慢主要是因为 STL的vector,扫描速度慢;,您可能会发现,hash_map是几乎无法在调试版本,你会看到。我注意到,当我第一次跑在x86调试基准,它似乎是"hungquot;。我停在调试器中,并发现它是运行quot;字符串hash_map:1添加itemsquot,测试。这个测试填充Hashtable的2.5万件,清除名单,并填写再而三更多的时间。那么,当插入一个明确的()命令后的第一个项目,hash_map卡住约4分钟做谁知道是什么,总运行时16分20秒(78倍更长的时间比发布版本)。我离开它运行在一夜之间,发现,去除测试甚至是更糟。这个测试试图删除10万件,但该列表的大小是有限的至2.5亿美元,使这些请求的最失败。无论出于何种原因,本次测试采取了10小时37分钟,这是9400倍以上的发行打造!
这竟然是由Visual C quot造成迭代debuggingquot;MIS的功能。 #定义_HAS_ITERATOR_DEBUGGING 0使其切实可能运行基准,但仍然十分缓慢调试Hashtable的测试构建。该图还显示,同一段代码可以运行在许多不同的速度取决于您的平台和编译器设置。对于例如,某些任务,特别是那些涉及64位整数(或更低程度,浮点运算),运行速度更快针对64时。一旦在一段时间,64处理一个任务更慢(由于某种原因,一个ifstream的读取文件:阅读()远在64位慢)。C#的结果是比较一致的: 事实上,只有少数几个操作是在一个较慢的显著C#中调试生成发布版本相比。其中一个原因是,NET标准库,称为BCL(基类库),即使优化当您正在运行调试版本。这就解释了为什么速度Dictionarylt,K,VGT,文件和字符串解析测试(其中主要强调BCL)中的几乎是在调试和发布版本相同。额外的优化似乎当C#调试版本启用调试器外运行,因为这些基准没有。事实上,在C#的x86调试构建超越了C X86调试建立在所有测试中,除了两个。但当然,我们真正关心的是Release版本。本文的其余部分将审查发布版本只(使用VisualStudio的默认编译器设置)。第三方benchmarksnbsp;
要添加更多的quot; realismquot;我的基准,我从另外两个人的三个基准。我重构自己的代码稍微,让代码更好地融入我的基准框架和两个基准,以改善消除2维数组C#版本,因为性能敏感的C#代码应该避免。我没有时间准备这些新的测试(或任何其它测试,对于这个问题,)ARM条形图。
我补充书面先生吸引力混沌。实际上有4个在他的测试基准,但一个测试字典,我已经为该基准,和一个测试一个特定的C正则表达式库,而我宁愿坚持标准库。第一基准,我一直是一个简单的为O(N ^ 3)矩阵乘法,第二个是一个高品质,但(我)难以遵循的数独解算器。再说,我从来没有玩过数独。
这两个基准最初写在C#中使用2维数组。现在,,笔者说:"这是我第一次写C#quot;学到更丰富的C#开发。NET的多维数组是没有良好的表现。他们的目的不是要快。相反,它可能会更好,以模拟使用二维数组与一维数组或quot; jaggedquot;双[] []而不是二维数组(双[,]).消除你的代码从一个多维数组最简单的方法是引入一个像这样的包装:

public struct Array2D<T> // use "class" if you prefer

{

  readonly T[] _a;

  readonly int _cols, _rows;

  

  public Array2D(int rows, int cols)

  {

    _a = new T[rows * cols];

    _cols = cols;

    _rows = rows;

  }

  public Array2D(T[] array, int cols)

  {

    _a = array;

    _cols = cols;

    _rows = _a.Length / cols;

  }

  

  public T[] InternalArray { get { return _a; } }

  public int Cols { get { return _cols; } }

  public int Rows { get { return _rows; } }

  

  // Add a range check on "col" if you want to sacrifice performance for safety

  public T this[int row, int col]

  {

    get { return _a[row * _cols + col]; }

    set { _a[row * _cols + col] = value; }

  }

};


在某些条件下,包装速度远远比标准。NET 2维数组(类型[N,N]),但作为基准显示,这已不再是一个可靠的优化,和你会往往从交错数组得到更好的结果。矩阵乘法测试在这个基准测试中,两个怪物1000X1000矩阵相乘。 C风格的乘法例行很简单,希望引起争议;内环优化quot; a_iquot;和"c_jquot;,以避免不必要的乘法,和quot; bquot;矩阵调换,因此它可以顺序访问。原来的版本可能只有方形矩阵相乘,但我把自由扩展到处理长方形的(未经测试,请注意)。{C}C#的变化在C#中有多种方式可以完成相同的任务。原来的版本使用多维数组(双[N,N]);我添加了三个方法,速度为了增加:Array2Dlt; doublegt;:如上所述,一维数组,二维的行为。双[N] [N]:一个quot; jaggedquot;阵列,这简直是一个数组的数组。因此,它需要更多的内存(16个额外的字节,每行相比Array2Dlt; doublegt;在x86下),和更多的初始化时间,但可以更快的整体。双[N * N]:一维数组指针的算术运算,就像C版本,访问。这将获得良好的性能,而不需要额外的内存。
您选择的方法使一个很大的区别:{S2}
正如你可以看到,基于指针的算术运算的版本(双[N * N)是最快的,锯齿状(双[N] [N])版本只是勉强slower.nbsp;
当你在x86的结果看(忽略单声道),双,显然是最慢约5.8秒。 Array2D是的近两倍在3.2秒快速。和双[N] [N]是两倍快1.6秒,。然而,64的结果是非常怪异。显然,微软针对x64优化多维数组,所以他们甚至比Array2D快。与此同时,有一个quot; glitchquot在x64/.NET4,使Array2D上,具体的JIT.nbsp版本缓慢;
注意:从现在开始,当我指的是"x86quot的,我不包括单声道,除非另有说明。 Mono是不是做得很好,到目前为止,并会继续做了很多这些测试不佳。事实上,我原本用于单声道深灰色的颜色。但那些极长的单声道酒吧成为一种分心,所以我把它改成浅灰色。就像我说的,如果你不使用Mono,不理会那些灰色长条。如果你使用Mono,那么,你看到Array2D栏关闭图表年底顺利吗?它的11.75 seconds.nbsp;
一个不变的是交错数组是多维数组更快。我还没有想出如何在大会上,看看发生了什么事情上还没有,但我能想到的原因有三为什么交错数组会更快。首先,NET范围检查所有的数组访问,除了里面一个for循环迭代从0到数组,锯齿状实施(主要是)能够做到年底。其次,当使用一个二维数组,这是不聪明的一个JIT将失败的因素,从内环乘法。第三,即使它出乘法的因素,它可能无法预先计算指针被检查的数组(事实上,GC可能使其很难做到这一点)的一部分。相比之下,锯齿版本需要没有乘法运算,我们可以清楚地缓存到当前行的矩阵的参考,像C版本。
使用指针的版本可避免单一附加在内环范围检查,所以应该稍快。
这整个讨论点,比C与C#中的表现一般的问题。。NET JITs是不是在为C编译器的优化好。这是很自然的,因为在运行时执行,使他们不能优化为积极(恐惧,该方案将启动太慢)JITs。在未来,人们可以想像聪明JITs产生一个缓慢的代码版本,然后(后一个循环执行数千次)超时以及优化C编译器的代码。他们已经拥有了一种接口调度优化技术。但一切的呢? No.nbsp;
因此,如果您需要快速的C#代码,您可能要优化自己:手动因素从内环表达式,切换到交错数组,甚至引入指针。手动优化可以是一个巨大的痛苦,但是,在这里面隐藏调用索引器的情况下,内环乘法。因此,你可以尝试,其结果没有被包括在这篇文章中。也许在下一次。 泛型VS templatesnbsp;
现在,主要的矩阵乘法测试采用双算术,但并不是所有的程序员都关注主要与双运算的速度。因此,我也写了测试的通用版本,所以你可以看到不同类型的数据,特别是int和float.nbsp的效果;
在本文中,我测试C#泛型,如果JIT可以优化以及C编译器的优化模板的第一个版本。结果似乎说是,但测试非常简单。对于这个矩阵乘法测试的延伸,我比较了5种不同的JIT引擎两种数据类型(双和int),并在一些案件中的JIT botches的工作。一看(LT;角度bracketsgt代表泛型):{S3}
(注:我扔在一个通用的浮点测试,这样你可以比较与C浮动测试,但我懒得手动编写其非泛型版本。)
当你在为x86使用整数的结果看,他们的罚款:通用LT; intgt;正是作为非通用INT相同的速度。但是,如果你看一下结果,为x64/.NET3,你会看到通用的双重考验,需要2.14x更长的时间,通用INT测试需要3.45x不再。 NET 4的JIT并没有那么糟糕,但它flubs整数测试一点点。单声道严重炸弹通用的测试,特别是涉及浮点运算(结果是9.7秒LT; doublegt;,和11.3秒LT; floatgt;)
,另一方面,表明绝对没有模板LT之间的差异; doublegt;版本和原来的非模板版本: {S4}的
注意,酒吧双[N * N]和LT; doublegt; [n * n的]是完全一样的。 C编译器在编译时使用令牌替换评估模板,所以没有理由期望有什么区别。因此,我没有理会一个非模板int或float版本的数字只是这样你可以比较他们与C#如果你想。
注:通用的测试,我小数淘汰的情况下矩阵的数据类型是quot; intquot;整数溢出过程中发生的乘法的,但希望这不会弄乱results.nbsp;C#与彗星
撇开仿制药的问题,并避免那些不可预知的二维数组的,让我们看到了C#与C比较。这个图表显示了原来的C版本和其直接的C#相当于,再加上[N] [N]版本,这是在C#更合适:{五}
的结果是显而易见的。首先,C胜在每一种情况下。如果您使用的x86 JIT,C#是只有一点点比C慢。但是,x64和单声道JITs的表现相当糟糕,在这个测试。需要注意的是交错数组版本(双[N] [N])是最合理的方式做大型矩阵乘法在C#,皱起了眉头,因为指针的算术运算在C#中文化后。你只使用锯齿状阵列版本,而不是指针的算术运算的版本宽松一点速度,但内存的成本(16B每行和慢GCS)应保持在mind.nbsp;独
这段代码的,有吸引力的混沌第二个基准,太长,张贴在这里。基本上,它涉及到很多数组访问,if语句和循环,但很少算术和没有浮点。因此,这种测试强调的编译器/ JIT的能力,以优化数组访问,寄存器分配和流量控制。
此测试使用了众多的一维数组和两个二维数组。像以前一样,我改用C#中的二维数组Array2D包装,其中增加的x86彗星#速度从6秒到5.2秒,但有可能伤害64的速度(我没有检查)。这里的结果:{中六}
从理论上讲,C应在本次测试的边缘,因为它使用数组巨资,它不是简单地从开始到结束像矩阵测试扫描阵列。在这种情况下,一个范围NET中插入检查所有的数组访问。同样,C只支持固定大小的小数组维度,而C#只支持动态轻微的数组维数,因此,例如,NET可以不优化的代码上的知识,所谓quot阵列; Cquot;始终是每秒16字节row.nbsp;
无论如何,VC胜大这个时候,通常运行快两倍。NET中,如果没有更多(单声道后方8.6秒,再次)。我的经验表明,数组范围检查不能占这么大的差别,但调查是阻碍,因为我仍然不知道如何在C#的优化组装。来吧,笑我。 !哈 Polynomialsnbsp;
{A6}是由A. D. Corlan。这是一个非常简单的测试,计算出一个100度的多项式使用float math.nbsp的价值;
我第一次跑这quot; Polynomialsquot在C#和C(VS 2008,x86)的基准测试,结果是C在0.034秒完成,和C#在7.085秒,C是208次的速度!当然,其他比C调试hash_map测试了10个小时以上,这是我见过的最极端的结果。 C结果似乎是不可能的:外层循环10万次迭代和两个内环每100次迭代,共2亿元迭代。有没有这么多的工作可以在0.034秒内完成,在2.83 GHz处理器的方式。事实上,在外层循环的大会,你可以看到,编译器做了一些惊人的:
		for(int i=0; i<Iterations; i++)

			pu += dopoly(x);

00CCB740  push        ecx  

00CCB741  fld         dword ptr [__real@3e4ccccd (0CD2D54h)] 

00CCB747  mov         dword ptr [esp+40h],0 

00CCB74F  fstp        dword ptr [esp] 

00CCB752  call        Polynomials::dopoly (0CCB650h) 

00CCB757  fstp        dword ptr [esp+40h] 

00CCB75B  fld         dword ptr [esp+40h] 

00CCB75F  add         esp,4 

00CCB762  mov         eax,989680h 

00CCB767  sub         eax,1 

00CCB76A  fld         st(0) 

00CCB76C  fadd        dword ptr [esp+38h] 

00CCB770  fstp        dword ptr [esp+38h] 

00CCB774  jne         Polynomials::Test+37h (0CCB767h) 


注意JNE分行0x0CCB767,多项式呼叫后:dopoly;调用该函数只有一次!莫名其妙的C优化想通了,dopoly()功能 - 也就是说,它总是返回相同的结果,相同的输入 - 因此它分解出的循环函数调用 !
虽然我真正优化的聪明印象深刻,这只是将不为基准。当时的想法是找出10万个电话dopoly()将采取多久,而不仅仅是一个呼叫。所以我做了一个小的变化:有内dopoly(堆栈上声明一个数组)。如果我动议数组调用函数,而是和它作为一个参数传递,优化器不再认为它可以分解出dopoly(),因此它被称为所需的10万次。这种变化增加了289倍的运行时间,从0.034秒至9.813 seconds.nbsp;
无论如何,这里的图: {七}
一般的C SSE2版本,在约24%,低于平均的C#版本(忽略Mono的伤心13秒。)的x87版本的C的时间完成,虽然是相当缓慢的。虽然我正在调查";聪明optimizerquot;上述问题,我想我看到的原因。我没有任何的x87专家,但看看这个。编译器展开dopoly第二循环()的10倍,但展开循环看起来像这样:
		for (j=0; j<100; j++)

			s = x*s + pol[j];

000DB696  fld         dword ptr [esp] 

000DB699  add         eax,28h 

000DB69C  sub         ecx,1 

000DB69F  fmul        st,st(1) 

000DB6A1  fadd        dword ptr [eax-30h] 

000DB6A4  fstp        dword ptr [esp] 

000DB6A7  fld         dword ptr [esp] 

000DB6AA  fmul        st,st(1) 

000DB6AC  fadd        dword ptr [eax-2Ch] 

000DB6AF  fstp        dword ptr [esp] 

000DB6B2  fld         dword ptr [esp] 

000DB6B5  fmul        st,st(1) 

000DB6B7  fadd        dword ptr [eax-28h] 

000DB6BA  fstp        dword ptr [esp] 

000DB6BD  fld         dword ptr [esp] 

000DB6C0  fmul        st,st(1) 

000DB6C2  fadd        dword ptr [eax-24h] 

000DB6C5  fstp        dword ptr [esp] 

...

它的反复存储和装载循环变量,第哎呀!C对C#:哈希tablesnbsp;
这个测试坑两种类型的。NET对词典相当于微软C hash_maps(或在VS2010 unordered_map)。首先,我想一个LT,INT,intgt;哈希表,然后LT;字符串,stringgt hashtable.The字符串测试使用相同的密钥为整数测试,但转换为字符串。每个测试10万整数转换为字符串(这是所有测试quot; 0quot;没有),所以你可能要弱智减去测试"0quot;所有的others.nbsp; 结果可能会让你大吃一惊:
{S8}
偶尔的例外,C#中赢得了压倒性的!一个特定的C情况下,X86与SSE2 VC10,运行速度比别人更好的处理字符串时,优于C#中。然而,在大多数情况下,VC失去了很大的时间。例如,第一次测试,运行快超过9倍。NET4 64到C VC10支持SSE2相比。
为什么相差这么大呢?好吧,我怀疑微软(Dinkumware)hash_map简直是可怕。我不知道它是如何实现的代码是如此丑陋我不能忍受连看都不看。老实说,谁缩进像这样的代码呢?
		// TEMPLATE CLASS _Hash

template<class _Traits>

	class _Hash

		: public _Traits	// traits serves as base class

	{	// hash table -- list with vector of iterators for quick access

public:

	typedef _Hash<_Traits> _Myt;

	typedef typename _Traits::_Val_type _Val_type;



	typedef typename _Traits::key_type key_type;

	typedef typename _Traits::key_compare key_compare;

	typedef typename _Traits::value_compare value_compare;

	enum

		{	// various constants

		_Bucket_size = key_compare::bucket_size,

		_Min_buckets = 8,	// min_buckets = 2 ^^ N, 0 < N

		_Multi = _Traits::_Multi};

	typedef list<typename _Traits::value_type,

		typename _Traits::allocator_type> _Mylist;


,至少他们补充一些意见VS 2010的版本。
无论如何,我可以肯定地说,它不是C编译器的错误。我知道{S10}{S11}我的我在
" {S13}类型。
public static T GenericSum<T, Math>(List<T> list, Math M) where Math : IMath<T>

{

	T sum = M.Zero;

	for (int i = 0; i < list.Count; i++)

		sum = M.Add(sum, list[i]);

	return sum;

} 
template<typename T>

T GenericSum(const vector<T>& list)

{

	T sum = (T)0;

	for(int i = 0; i < (int)list.size(); i++)

		sum += list[i];

	return sum; 

} 
跆拳道?为什么不呢?那是什么约?
double total = 0;

for (int i = 0; i < Iterations; i++)

	total = total - total / 4.0 + (double)i % 100000 * 3.0; 










的问候,
感谢问候,

回答