返回首页

简介
我发现有关代码的合同在本月初的MSDN非常令人兴奋的文章。我不知道这个功能,NET 4.0中,在阅读文章之前,和asnbsp;的复杂的应用程序的开发者保持一个非常大的andnbsp的团队的经理,我总是在技术,提高代码质量和正确性。我不会老调重弹,在这篇文章中的有关代码合同有趣的细节。 {A}到Microsoft DevLabs下载页面,你需要运行下面的代码。
阅读MSDN文章时,我首先想到的是,带来的好处,必须拿出一些价格,和我最初关注的是对性能的影响。合同是在运行时执行自定义代码在编译时插入,每当其他一些进程将代码添加到矿山,我担心隐藏的性能成本。
我写了下面的小应用程序得到一些指标和评估如何昂贵的合同相比,可以用来验证前和执行后条件的其他技术。使用代码
MSDN文章的作者使用一个简单的计算器功能,突出合同的好处。我将使用相同​​的基本功能:

private static Int32 Add(Int32 x, Int32 y) {

   if (x == y)

      return x * 2;



   return x + y;

}

额外的,如果在那里的声明只是为了加强加入条件后​​,到处检查你的代码,你过早退出的难度。我要离开这里的分析。 "IF - THEN - Throwquot;
的方法来检查前,后的条件是使用明确的,如果语句以验证您的输入参数和输出结果。所有的前,后的条件,我们在这里加入是完全任意的,但自然会在所有的例子一致。{C}Debug.Assert的
另一种方法是使用Debug.Assert的():
private static Int32 AssertCheckedAdd(Int32 x, Int32 y) {

   System.Diagnostics.Debug.Assert(x >= 0);



   if (x == y) {

      System.Diagnostics.Debug.Assert(x * 2 >= 0);



      return x * 2;

   }



   System.Diagnostics.Debug.Assert(x + y >= 0);

   return x + y;

}
合同
最后的方法来检查是有趣的新的代码约定:
private static Int32 ContractCheckedAdd(Int32 x, Int32 y) {



   Contract.Requires(x >= 0, "X must be greater than 0");

   Contract.Ensures(Contract.Result<Int32>() >= 0, "Result must be positive");



   if (x == y)

      return x * 2;



   return x + y;

}

的合同,你不必担心你退出的好处之一。后检查条件都集中在方法的顶部。运行的不同方法
我定时亿次以上的方法执行了多长时间。
private delegate Int32 testMethod(Int32 x, Int32 y);



static void Main(string[] args) {

   const Int32 ITERATIONS = 10000;



   foreach (testMethod tm in new testMethod[] { new testMethod(Add), 

                                    new testMethod(IfCheckedAdd), 

                                    new testMethod(AssertCheckedAdd),

                                    new testMethod(ContractCheckedAdd) }) {

   DateTime start = DateTime.Now;



   for (Int32 i = 0; i < ITERATIONS; i++)

      for (Int32 j = 0; j < ITERATIONS; j++)

         tm(i, j);



      System.Console.WriteLine(tm.Method.Name + " " + 

	(DateTime.Now - start).TotalMilliseconds.ToString());

   }

}
安装
我运行应用程序的5倍,平均次数和结果的可变性的感觉。执行这些测试是在Windows 7(32位),双核心(英特尔酷睿2 E8400 3.0GHz处理器)的RAM。

的4Gb的CPU我用的代码合同SDK与前版本1.4.40314.1和检查后合同启用。

我不感兴趣,在执行的不同方法的表现时前或后的条件不具备,只是不同的验证框架的开销。
结果调试添加IF - THEN -抛出断言合同运行1(MS)2199.62230.83213.6运行21950.02184.02215.2运行31950.02199.62246.43260.4运行41950.02246.42293.23369.6运行51934.42184.02246.43244.8平均1940.62202.72246.43266.6标准偏差8.5425.6329.1860.0113.5%1.98%45.42% 15.76%68.33% 表1。结果从运行调试内置在Visual Studio 2008代码

回答

评论会员:GlobX 时间:2012/01/27
?酷的文章,我只是不知道的代码约定的绩效评价的价值是什么
评论会员:游客 时间:2012/01/27
ScruffyDuck:|我只打了周围的代码契约。但是,他们作为确保条件,可在有条不紊地进行检查的方式向我提出上诉。您的文章,促使我采取在代码合同再看看我的工作。谢谢。乔恩ScruffyDuck软件kornman00:微软MVP
|一个迷人的洞察力,感谢
评论会员:肖恩迈克尔墨菲 时间:2012/01/27
你为什么不测试,或包括额外的测试与Requireslt任何理由; TGT;覆盖!我知道VSM的文章中使用的覆盖(在失败时抛出一个新实例的T),但看到你的文章只是用香草机制。异常覆盖,您的合同仍然会进行测试ReleaseRequires构建(下运行时检查CC设置),而只是将抛出异常,并没有别的(IIRC)

(我只用在VS2010 CC)
评论会员:杰里米哈钦森 时间:2012/01/27
kornman00写道:你为什么不测试,或包括额外的测试与Requireslt任何理由; TGT;覆盖
?没有,没有特别的理由。该文档没有给选择一个比其他的原因。

分享和欣赏。
肖恩
评论会员:肖恩迈克尔墨菲 时间:2012/01/27
。我发现你的文章有趣,我还没有看过代码约定,所以我第一次引进以及担任(很酷的东西)

我的意见后,我下载了你的代码,并做了评论员建议。

1。我与System.Diagnostic.StopWatch取代的DateTime。
正如你所说的准确性可能不是一个问题很多,但只是要确定。2。我开始时间前一次调用的每个方法
3。我编译的释放模式(我不关心Debug.Assert的(性能),它不会在生产中运行反正

作为VS托管过程,然后我跑的代码,并不断得到数字,比如:
新增693
IfCheckedAdd 806
AssertCheckedAdd 688
ContractCheckedAdd 694

然后,我作为一个单独的进程运行的代码(双击的exe),始终得到了像这些数字:
新增408
IfCheckedAdd 408
AssertCheckedAdd 408
ContractCheckedAdd 408
代码合约的表现,而你的文章没有教我很多,它没有我介绍给他们,我真的学到了很多关于测量通过的意见的性能。
大外卖 - 始终测量在释放模式
编译一个独立的过程中的表现
评论会员:。肖恩迈克尔墨菲 时间:2012/01/27
然后必须的Visual Studio环境外,因为我的数字是可重复,显示性能上的损失,合同在Visual Studio中调试和运行释放的DOS提示符。
代码外
我看不出如何就不可能有一个点球,因为你正在运行的额外的代码。

反馈...
肖恩
评论会员:杰里米哈钦森 时间:2012/01/27
杰里米哈钦森说:然后,我作为一个单独的进程运行的代码(双击的exe),始终得到了这样的数字:
新增408
IfCheckedAdd 408
AssertCheckedAdd 408
ContractCheckedAdd 408

嘿,你使用VS2010的?你可以看看不同的方法生成的IL吗?可能编译器优化检查代码,因为它知道它永远不会被运行?

感谢
评论会员:Xetrill 时间:2012/01/27
LT引用文字类="FQ"GT,LT,科类="常见问题解答"GT肖恩迈克尔墨菲写道:LT / divgt;嘿,您使用的是VS2010的?你可以看看不同的方法生成的IL吗?可能编译器优化检查代码,因为它知道它永远不会被运行LT; brgt; LT / blockquotegt;

其实,我跑了从VS2008和VS2010的构建测试中都得到了类似的结果。我也试图在x86,x64和AnyCPU编译。每个建设呈跨越4种方法一致的结果。我有点惊讶,x86版本是慢一点(〜530),我认为64位是不应该是有益的,除非你用巨大的内存桩的。

这是我第一次在白细胞介素,我不能真正遵循它,但添加,AssertCheckedAdd和ContractCheckedAdd都一样,一行行。 IfCheckedAdd了很多它。
然后,我测试通过的恶劣条件和ContractCheckedAdd是不是抛出一个异常,这让我感到惊讶。
原来,当我下载的这篇文章默认情况下,代码"执行运行时检查"未被选中(我下载,以确保第二次)的合同。有一次,我检查,白细胞介素ContractCheckedAdd改变,它需要更长的时间。现在我的时间看起来像

新增413
IfCheckedAdd 410
AssertCheckedAdd 410
ContractCheckedAdd 692

它仍然是奇数IfCheckedAdd,花费较少的时间比添加。无论哪种方式,我会说,合同的执行死刑的,看起来是值得的。唯一超过100万次迭代过程中.3秒
评论会员:肖恩迈克尔墨菲 时间:2012/01/27
。有趣的想法,但缺乏执行...

你根本无法使用datetime做准确的基准,使用秒表性能计数器
NBSP依赖;
此外,第一次一个方法是把它称为获取JITed,因此,你应该调用的每个方法
另一种方式,以增加测试。精度可能会强制GC运行,并等待它完成,然后以基准

我想知道,因为你使用Debug.Assert的,只执行/编译如果调试符号宣布。你调试生成测量吗?甚至从一个托管的VS过程中

PS为什么你通过委托调用
评论会员:?沃纳面包车芬特尔 时间:2012/01/27
Xetrill写道:"你根本无法使用datetime不定时个别运行的方法,使hyperaccuracy是不需要做准确benchmarkingI'm。只要测试都是定时以同样的方式的结果是相关的。

Xetrill写道:另一种方式来提高测试的准确性可能会迫使GC runInteresting想法。开始前每个测试运行和后的结果后,我将添加一个GC.Collect的()调用。

Xetrill写道:你调试测量的建立是Debug.Assert的()方法可以进行比较?。运行发布内置的测试原因Debug.Assert的()添加(类似)的时间。我会后释放时间后

Xetrill写道:P.S.你为什么通过委托调用只是为了保持调用的代码整洁
评论会员:。肖恩迈克尔墨菲 时间:2012/01/27
Debug.Assert的方法,如是调试的条件,并不会被调用时释放模式。代码合约相同的条件调用时,在调试模式下运行,弹出断言对话框等。在释放模式中,我敢肯定这将执行好了很多,因为他们应该扩大到非常基本的检查和少得多的方法的调用。

我会好奇地看到其中的差别,我只是有点懒惰的权利,现在运行它自己,但如果/当我做我会让你知道
评论会员:MW_Justin 时间:2012/01/27
沃纳面包车芬特尔写道:我想好奇,想看看differenceThe释放时间是绝对快,但仍然显示了显著合同的相对刑罚。我会后
:肖恩迈克尔墨菲
评论会员:游客 时间:2012/01/27
您好肖恩,我注意到,你使用VisualStudio2008。我重新编译与2010年上运行我的电脑和代码合​​约中表现最好的一群甚至快于添加在我的一些运行。我没有2008,但如果你能后运行的二进制文件,它会很有趣,看看它是编译器或环境,创造了不同的结果。无论如何,文章表示感谢。〜Justin_H