<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jon Skeet: Coding Blog : Benchmarking, Stack Overflow, C#</title><link>http://msmvps.com/blogs/jon_skeet/archive/tags/Benchmarking/Stack+Overflow/C_2300_/default.aspx</link><description>Tags: Benchmarking, Stack Overflow, C#</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Revisiting randomness</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx</link><pubDate>Wed, 04 Nov 2009 07:40:15 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1737577</guid><dc:creator>skeet</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1737577</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1737577</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx#comments</comments><description>&lt;p&gt;Almost every Stack Overflow question which includes the words &amp;quot;random&amp;quot; and &amp;quot;repeated&amp;quot; has the same basic answer. It&amp;#39;s one of the most common &amp;quot;gotchas&amp;quot; in .NET, Java, and no doubt other platforms: creating a new random number generator without specifying a seed will depend on the current instant of time. The current time as measured by the computer doesn&amp;#39;t change very often compared with how often you can create and use a random number generator – so code which repeatedly creates a new instance of Random and uses it once will end up showing a lot of repetition.&lt;/p&gt;  &lt;p&gt;One common solution is to use a static field to store a single instance of Random and reuse it. That&amp;#39;s okay in Java (where Random is thread-safe) but it&amp;#39;s not so good in .NET – if you use the same instance repeatedly from .NET, you can corrupt the internal data structures.&lt;/p&gt;  &lt;p&gt;A long time ago, I created a &lt;a href="http://pobox.com/~skeet/csharp/miscutil/usage/staticrandom.html"&gt;StaticRandom class&lt;/a&gt; in &lt;a href="http://pobox.com/~skeet/csharp/miscutil"&gt;MiscUtil&lt;/a&gt; – essentially, it was just a bunch of static methods (to mirror the instance methods found in Random) wrapping a single instance of Random and locking appropriately. This allows you to just call StaticRandom.Next(1, 7) to roll a die, for example. However, it has a couple of problems:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;It doesn&amp;#39;t scale well in a multi-threaded environment. When I originally wrote it, I benchmarked an alternative approach using [ThreadStatic] and at the time, locking won (at least on my computer, which may well have only had a single core). &lt;/li&gt;    &lt;li&gt;It doesn&amp;#39;t provide any way of getting at an instance of Random, other than by using new Random(StaticRandom.Next()). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The latter point is mostly a problem because it encourages a style of coding where you just use StaticRandom.Next(…) any time you want a random number. This is undoubtedly convenient in some situations, but it goes against the idea of &lt;a href="http://stackoverflow.com/questions/1667516/doesnt-passing-in-parameters-that-should-be-known-implicitly-violate-encapsulati/1667590#1667590"&gt;treating a source of randomness as a service or dependency&lt;/a&gt;. It makes it harder to get repeatability and to see what needs that dependency.&lt;/p&gt;  &lt;p&gt;I could have just added a method generating a new instance into the existing class, but I decided to play with a different approach – going back to per-thread instances, but this time using the &lt;a href="http://msdn.microsoft.com/en-us/library/dd642243(VS.100).aspx"&gt;ThreadLocal&amp;lt;T&amp;gt; class&lt;/a&gt; introduced in .NET 4.0. Here&amp;#39;s the resulting code:&lt;/p&gt;  &lt;div class="code"&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System;     &lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Threading;     &lt;br /&gt;    &lt;br /&gt;&lt;span class="Namespace"&gt;namespace&lt;/span&gt; RandomDemo     &lt;br /&gt;{     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// Convenience class for dealing with randomness.&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; ThreadLocalRandom     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// Random number generator used to generate seeds,&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// which are then used to create new random number&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// generators on a per-thread basis.&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;readonly&lt;/span&gt; Random globalRandom = &lt;span class="Keyword"&gt;new&lt;/span&gt; Random();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;readonly&lt;/span&gt;&amp;#160;&lt;span class="ReferenceType"&gt;object&lt;/span&gt; globalLock = &lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;#160;&lt;span class="ReferenceType"&gt;object&lt;/span&gt;();     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// Random number generator &lt;/span&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;readonly&lt;/span&gt; ThreadLocal&amp;lt;Random&amp;gt; threadRandom = &lt;span class="Keyword"&gt;new&lt;/span&gt; ThreadLocal&amp;lt;Random&amp;gt;(NewRandom);     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// Creates a new instance of Random. The seed is derived &lt;/span&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// from a global (static) instance of Random, rather &lt;/span&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// than time.&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt; Random NewRandom()     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;lock&lt;/span&gt; (globalLock)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;return&lt;/span&gt;&amp;#160;&lt;span class="Keyword"&gt;new&lt;/span&gt; Random(globalRandom.Next());     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// Returns an instance of Random which can be used freely&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// within the current thread.&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt; Random Instance { get { &lt;span class="Statement"&gt;return&lt;/span&gt; threadRandom.Value; } }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;See &amp;lt;see cref=&amp;quot;Random.Next()&amp;quot; /&amp;gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;int&lt;/span&gt; Next()     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;return&lt;/span&gt; Instance.Next();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;See &amp;lt;see cref=&amp;quot;Random.Next(int)&amp;quot; /&amp;gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;int&lt;/span&gt; Next(&lt;span class="ValueType"&gt;int&lt;/span&gt; maxValue)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;return&lt;/span&gt; Instance.Next(maxValue);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;See &amp;lt;see cref=&amp;quot;Random.Next(int, int)&amp;quot; /&amp;gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;int&lt;/span&gt; Next(&lt;span class="ValueType"&gt;int&lt;/span&gt; minValue, &lt;span class="ValueType"&gt;int&lt;/span&gt; maxValue)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;return&lt;/span&gt; Instance.Next(minValue, maxValue);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;See &amp;lt;see cref=&amp;quot;Random.NextDouble()&amp;quot; /&amp;gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;double&lt;/span&gt; NextDouble()     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Statement"&gt;return&lt;/span&gt; Instance.NextDouble();     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="XmlComment"&gt;/// &amp;lt;summary&amp;gt;See &amp;lt;see cref=&amp;quot;Random.NextBytes(byte[])&amp;quot; /&amp;gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;void&lt;/span&gt; NextBytes(&lt;span class="ValueType"&gt;byte&lt;/span&gt;[] buffer)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Instance.NextBytes(buffer);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;} &lt;/div&gt;  &lt;p&gt;The user can still call the static Next(…) methods if they want, but they can also get at the thread-local instance of Random by calling ThreadLocalRandom.Instance – or easily create a new instance with ThreadLocalRandom.NewRandom(). (The fact that NewRandom uses the global instance rather than the thread-local one is an implementation detail really; it happens to be convenient from the point of view of the ThreadLocal&amp;lt;T&amp;gt; constructor. It wouldn&amp;#39;t be terribly hard to change this.)&lt;/p&gt;  &lt;p&gt;Now it&amp;#39;s easy to write a method which needs randomness (e.g. to shuffle a deck of cards) and give it a Random parameter, then call it using the thread-local instance:&lt;/p&gt;  &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;#160;&lt;span class="ValueType"&gt;void&lt;/span&gt; Shuffle(Random rng)     &lt;br /&gt;{     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ...     &lt;br /&gt;}     &lt;br /&gt;...     &lt;br /&gt;deck.Shuffle(ThreadLocalRandom.Instance); &lt;/div&gt;  &lt;p&gt;The Shuffle method is then easier to test and debug, and expresses its dependency explicitly.&lt;/p&gt;  &lt;h3&gt;Performance&lt;/h3&gt;  &lt;p&gt;I tested the &amp;quot;old&amp;quot; and &amp;quot;new&amp;quot; implementations in a very simple way – for varying numbers of threads, I called Next() a fixed number of times (from each thread) and timed how long it took for all the threads to finish. I&amp;#39;ve also tried a .NET-3.5-compatible version using ThreadStatic instead of ThreadLocal&amp;lt;T&amp;gt;, and running the original code and the ThreadStatic version on .NET 3.5 as well.&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td align="right"&gt;Threads&lt;/td&gt;        &lt;td align="right"&gt;StaticRandom (4.0b2)&lt;/td&gt;        &lt;td align="right"&gt;ThreadLocalRandom (4.0b2)&lt;/td&gt;        &lt;td align="right"&gt;ThreadStaticRandom (4.0b2)&lt;/td&gt;        &lt;td align="right"&gt;StaticRandom(3.5)&lt;/td&gt;        &lt;td align="right"&gt;ThreadStaticRandom (3.5)&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td align="right"&gt;1&lt;/td&gt;        &lt;td align="right"&gt;11582&lt;/td&gt;        &lt;td align="right"&gt;6016&lt;/td&gt;        &lt;td align="right"&gt;10150&lt;/td&gt;        &lt;td align="right"&gt;10373&lt;/td&gt;        &lt;td align="right"&gt;16049&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td align="right"&gt;2&lt;/td&gt;        &lt;td align="right"&gt;24667&lt;/td&gt;        &lt;td align="right"&gt;7214&lt;/td&gt;        &lt;td align="right"&gt;9043&lt;/td&gt;        &lt;td align="right"&gt;25062&lt;/td&gt;        &lt;td align="right"&gt;17257&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td align="right"&gt;3&lt;/td&gt;        &lt;td align="right"&gt;38095&lt;/td&gt;        &lt;td align="right"&gt;10295&lt;/td&gt;        &lt;td align="right"&gt;14771&lt;/td&gt;        &lt;td align="right"&gt;36827&lt;/td&gt;        &lt;td align="right"&gt;25625&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td align="right"&gt;4&lt;/td&gt;        &lt;td align="right"&gt;49402&lt;/td&gt;        &lt;td align="right"&gt;13435&lt;/td&gt;        &lt;td align="right"&gt;19116&lt;/td&gt;        &lt;td align="right"&gt;47882&lt;/td&gt;        &lt;td align="right"&gt;34415&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;A few things to take away from this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The numbers were slightly erratic; somehow it was quicker to do twice the work with ThreadStaticRandom on .NET 4.0b2! This isn&amp;#39;t the perfect benchmarking machine; we&amp;#39;re interested in trends rather than absolute figures. &lt;/li&gt;    &lt;li&gt;Locking hasn&amp;#39;t changed much in performance between framework versions &lt;/li&gt;    &lt;li&gt;ThreadStatic has improved &lt;em&gt;massively&lt;/em&gt; between .NET 3.5 and 4.0 &lt;/li&gt;    &lt;li&gt;Even on 3.5, ThreadStatic wins over a global lock as soon as there&amp;#39;s contention &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The only downside to the ThreadLocal&amp;lt;T&amp;gt; version is that it requires .NET 4.0 - but the ThreadStatic version works pretty well too.&lt;/p&gt;  &lt;p&gt;It&amp;#39;s worth bearing in mind that of course this is testing the highly unusual situation where there&amp;#39;s a &lt;em&gt;lot&lt;/em&gt; of contention in the global lock version. The performance difference in the single-threaded version where the lock is always uncontended is still present, but very small.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;After reading the comments and thinking further, I would indeed get rid of the static methods elsewhere. Also, for the purposes of dependency injection, I agree that it&amp;#39;s a good idea to have a factory interface &lt;em&gt;where that&amp;#39;s not overkill&lt;/em&gt;. The factory implementation could use either the ThreadLocal or ThreadStatic implementations, or effectively use the global lock version (by having its own instance of Random and a lock). In many cases I&amp;#39;d regard that as overkill, however.&lt;/p&gt;  &lt;p&gt;One other interesting option would be to create a thread-safe instance of Random to start with, which delegated to thread-local &amp;quot;normal&amp;quot; implementations. That would be very useful from a DI standpoint.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1737577" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Parallelisation/default.aspx">Parallelisation</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Stack+Overflow/default.aspx">Stack Overflow</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Benchmarking/default.aspx">Benchmarking</category></item><item><title>Benchmarking: designing an API with unusual goals</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/02/02/benchmarking-designing-an-api-with-unusual-goals.aspx</link><pubDate>Mon, 02 Feb 2009 20:10:21 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1668242</guid><dc:creator>skeet</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1668242</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1668242</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/02/02/benchmarking-designing-an-api-with-unusual-goals.aspx#comments</comments><description>&lt;p&gt;In a couple of recent posts I&amp;#39;ve written about a &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2009/01/26/benchmarking-made-easy.aspx"&gt;benchmarking framework&lt;/a&gt; and the &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2009/01/29/for-vs-foreach-on-arrays-and-lists.aspx"&gt;results it produced for using for vs foreach in loops&lt;/a&gt;. I&amp;#39;m pleased with what I&amp;#39;ve done so far, but I don&amp;#39;t think I&amp;#39;ve gone far enough yet. In particular, while it&amp;#39;s good at testing multiple algorithms against a single input, it&amp;#39;s not good at trying several different inputs to demonstrate the complexity vs input size. I wanted to rethink the design at three levels - what the framework would be capable of, how developers would use it, and then the fine-grained level of what the API would look like in terms of types, methods etc. These may all sound quite similar on the face of it, but this project is somewhat different to a lot of other coding I&amp;#39;ve done, mostly because I want to lower the barrier to entry as far as humanly possible.&lt;/p&gt;  &lt;p&gt;Before any of this is meaningful, however, I really needed an idea of the fundamental goal. Why was I writing yet another benchmarking framework anyway? While I normally cringe at mission statements because they&amp;#39;re so badly formulated and used, I figured this time it would be helpful.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Minibench makes it &lt;strong&gt;easy&lt;/strong&gt; for &lt;strong&gt;developers&lt;/strong&gt; to &lt;strong&gt;write&lt;/strong&gt; and &lt;strong&gt;share&lt;/strong&gt; tests to &lt;strong&gt;investigate&lt;/strong&gt; and &lt;strong&gt;measure&lt;/strong&gt; code &lt;strong&gt;performance&lt;/strong&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The words in bold (or for the semantically inclined, the strong words) are the real meat of it. It&amp;#39;s quite scary that even within a single sentence there are seven key points to address. Some are quite simple, others cause grief. Now let&amp;#39;s look at each of the areas of design in turn.&lt;/p&gt;  &lt;p&gt;Each element of the design should either clearly contribute to the mission statement or help in a non-functional way (e.g. make the project feasible in a reasonable timeframe, avoid legal issues etc). I&amp;#39;m aware that with the length of this post, it sounds like I&amp;#39;m engaging in &amp;quot;big upfront design&amp;quot; but I&amp;#39;d like to think that it&amp;#39;s at least informed by my recent attempt, and that the design criteria here are statements of intent rather than implementation commitments. (Aargh, buzzword bingo... please persevere!)&lt;/p&gt;  &lt;h3&gt;What can it do?&lt;/h3&gt;  &lt;p&gt;As we&amp;#39;ve already said, it&amp;#39;s got to be able to measure code performance. That&amp;#39;s a pretty vague definition, however, so I&amp;#39;m going to restrict it a bit - the design is as much about saying what &lt;em&gt;isn&amp;#39;t&lt;/em&gt; included as what &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Each test will take the form of a single piece of code which is executed many times by the framework. It will have an input and an expected output. (Operations with no natural output can return a constant; I&amp;#39;m not going to make any special allowance for them.) &lt;/li&gt;    &lt;li&gt;The framework should take the tedium out of testing. In particular I don&amp;#39;t want to have to run it several times to get a reasonable number of iterations. I &lt;em&gt;suspect&lt;/em&gt; it won&amp;#39;t be feasible to get the framework to guess appropriate inputs, but that would be lovely if possible. &lt;/li&gt;    &lt;li&gt;Only wall time is measured. There are loads of different metrics which &lt;em&gt;could&lt;/em&gt; be applied: CPU execution time, memory usage, IO usage, lock contention - all kinds of things. Wall time (i.e. actual time elapsed, as measured by a clock on the wall) is by far the simplest to understand and capture, and it&amp;#39;s the one most frequently cited in newsgroup and forum questions in my experience. &lt;/li&gt;    &lt;li&gt;The benchmark is uninstrumented. I&amp;#39;m not going to start rewriting your code dynamically. Frankly this is for reasons of laziness. A really professional benchmarking system might take your IL and wrap it in a timing loop within a single method, somehow enforcing that the result of each iteration is used. I don&amp;#39;t believe that&amp;#39;s worth my time and energy, as well as quite possibly being beyond my capabilities. &lt;/li&gt;    &lt;li&gt;As a result of the previous bullet, the piece of code to be run lots of times needs to be non-trivial. The reality is that it&amp;#39;ll end up being called as a delegate. This is pretty quick, but if you&amp;#39;re just testing &amp;quot;is adding two doubles faster or slower than adding two floats&amp;quot; then you&amp;#39;ll need to put a bit more work in (e.g. having a loop in your own code as well). &lt;/li&gt;    &lt;li&gt;As well as the use case of &amp;quot;which of these algorithms performs the best with this input?&amp;quot; I want to support &amp;quot;how does the performance vary as a function of the input?&amp;quot; This should support multiple algorithms at the same time as multiple inputs. &lt;/li&gt;    &lt;li&gt;The output should be flexible but easy to describe in code. For single-input tests simple text output is fine (although the exact figures to produce can be interesting); for multiple inputs against multiple tests a graph would often be ideal. If I don&amp;#39;t have the energy to write a graphing output I should at least support writing to CSV or TSV so that a spreadsheet or graphing tool can do the heavy lifting. &lt;/li&gt;    &lt;li&gt;The output should be &lt;em&gt;useful&lt;/em&gt; - it should make it easy to compare the performance of different algorithms and/or inputs. It&amp;#39;s clear from the previous post here that &lt;em&gt;just&lt;/em&gt; including the scaled score doesn&amp;#39;t give an obvious meaning. Some careful wording in the output, as well as labeled columns, may be required. This is emphatically &lt;em&gt;not&lt;/em&gt; a dig at anyone confused by the last post - any confusion was my own fault.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Okay, that doesn&amp;#39;t sound too unreasonable. The next area is much harder, in my view.&lt;/p&gt;  &lt;h3&gt;How does a developer use it?&lt;/h3&gt;  &lt;p&gt;Possibly the most important word in the mission statement is &lt;strong&gt;share&lt;/strong&gt;. The reason I started this project at all is that I was fed up with spending ages writing timing loops for benchmarks which I&amp;#39;d then post on newsgroups or Stack Overflow. That means there are two (overlapping) categories of user:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;A developer writing a test. This needs to be easy, but that&amp;#39;s an aspect of design that I&amp;#39;m reasonably familiar with. I&amp;#39;m not saying I&amp;#39;m &lt;em&gt;good&lt;/em&gt; at it, but at least I have some prior experience. &lt;/li&gt;    &lt;li&gt;A developer reading a newsgroup/forum post, and wanting to run the benchark for themselves. This distribution aspect is the hard bit - or at least the bit requiring imagination. I want the barrier to running the code to be really, &lt;em&gt;really&lt;/em&gt; low. I suspect that there&amp;#39;ll be a &amp;quot;fear of the unknown&amp;quot; to start with which is hard to conquer, but if the framework becomes widely used I want the reader&amp;#39;s reaction to be: &amp;quot;Ah, there&amp;#39;s a MiniBench for this. I&amp;#39;m confident that I can download and run this code with almost no effort.&amp;quot; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This second bullet is the one that my friend Douglas and I have been discussing over the weekend, in some ways playing a game of one-upmanship: &amp;quot;I can think of an idea which is &lt;em&gt;even easier&lt;/em&gt; than yours.&amp;quot; It&amp;#39;s a really fun game to play. Things we&amp;#39;ve thought about so far:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;A web page which lets you upload a full program (without the framework) and spits out a URL which can be posted onto Stack Overflow etc. The user would then choose from the following formats: &lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Single .cs file containing the whole program - just compile and run. (This would also be shown on the download page.) &lt;/li&gt;      &lt;li&gt;Test code only - for those whole already have the framework &lt;/li&gt;      &lt;li&gt;Batch file - just run it to extract/build/run the C# code. &lt;/li&gt;      &lt;li&gt;NAnt project file containing the C# code embedded in it - just run NAnt &lt;/li&gt;      &lt;li&gt;MSBuild project file - ditto but with msbuild. &lt;/li&gt;      &lt;li&gt;Zipped project – open the project to load the test in one file and the framework code in other (possibly separate) .cs files &lt;/li&gt;      &lt;li&gt;Zipped solution – open to load two projects: the test code in one and the framework in the other &lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;A web page which which lets you upload your results and browse the results of others &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Nothing&amp;#39;s finalised here, but I like the general idea. I&amp;#39;ve managed (fairly easily) to write a &amp;quot;self-building&amp;quot; batch file, but I haven&amp;#39;t tried with NAnt/MSBuild yet. I can&amp;#39;t imagine it&amp;#39;s that hard - but then I&amp;#39;m not sure how much value there is either. What I &lt;em&gt;do&lt;/em&gt; want to try to aim for is users running the tests properly, first time, without much effort. Again, looking back at the last post, I want to make it obvious to users if they&amp;#39;re running under a debugger, which is almost always the wrong thing to be doing. (I&amp;#39;m pretty sure there&amp;#39;s an API for this somewhere, and if there&amp;#39;s not I&amp;#39;m sure I can work out an evil way of detecting it anyway.)&lt;/p&gt;  &lt;p&gt;The main thing is the ease of downloading and running the benchmark. I can&amp;#39;t see how it could be much easier than &amp;quot;follow link; choose format and download; run batch file&amp;quot; - unless the link itself was to the batch file, of course. (That would make it harder to use for people who wanted to get the source in a more normal format, of course.)&lt;/p&gt;  &lt;p&gt;Going back to the point of view of the developer writing the test, I need to make sure it&amp;#39;s easy enough for &lt;em&gt;me&lt;/em&gt; to use from home, work and on the train. That &lt;em&gt;may&lt;/em&gt; mean a web page where I can just type in code, the input and expected output, and let it fill in the rest of the code for me. It &lt;em&gt;may&lt;/em&gt; mean compiling a source file against a library from the command line. It &lt;em&gt;may&lt;/em&gt; mean compiling a source file against the source code of the framework from the command line, with the framework code all in one file. It &lt;em&gt;may&lt;/em&gt; mean building in Visual Studio. I&amp;#39;d like to make all of these cases as simple as possible - which is likely to make it simple for other developers as well. I&amp;#39;m not planning on optimising the experience when it comes to writing a benchmark on my mobile though - that might be a step too far!&lt;/p&gt;  &lt;h3&gt;What should the API look like?&lt;/h3&gt;  &lt;p&gt;When we get down to the nitty-gritty of types and methods, I think what I&amp;#39;ve got is a good starting point. There are still a few things to think about though:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;We &lt;em&gt;nearly&lt;/em&gt; have the functionality required for running a suite with different inputs already - the only problem is that we&amp;#39;re specifying the input (and expected output) in the constructor rather than as parameters to the RunTests method. I could change that... but then we lose the benefit of type inference when creating the suite. I haven&amp;#39;t resolved this to my satisfaction yet :(&lt;/li&gt;    &lt;li&gt;The idea of having the suite automatically set up using attributed methods appeals, although we&amp;#39;d still need a Main method to create the suite and format the output. The suite creation can be simplified, but the chances of magically picking the most appropriate output are fairly slim. I suppose it could go for the &amp;quot;scale to best by number of iterations and show all columns&amp;quot; option by default... that still leaves the input and expected output, of course. I&amp;#39;m sure I&amp;#39;ll have &lt;em&gt;something&lt;/em&gt; like this as an option, but I don&amp;#39;t know how far it will go.&lt;/li&gt;    &lt;li&gt;The &amp;quot;configuration&amp;quot; side of it is expressed as a couple of constants at the moment. These control the minimum amount of time to run tests for before we believe we&amp;#39;ll be able to guess how many iterations we&amp;#39;ll need to get close to the target time, and the target time itself. These are currently set at 2 seconds and 30 seconds respectively - but when running tests just to check that you&amp;#39;ve got the right output format etc, that&amp;#39;s far too long. I suspect I should make a test suite have a configuration, and &lt;em&gt;default&lt;/em&gt; to those constants but allow them to be specified on the command line as well, or explicitly in code.&lt;/li&gt;    &lt;li&gt;Why do we need to set the expected output? In many cases you can be pretty confident that at least &lt;em&gt;one&lt;/em&gt; of the test cases will be correct - so it&amp;#39;s probably simpler just to run each test once and check that the results are the same for all of them, and take that as the expected output. If you don&amp;#39;t have to specify the expected output, it becomes easier to specify a sequence of inputs to test.&lt;/li&gt;    &lt;li&gt;Currently BenchmarkResult is nongeneric. This makes things simpler internally - but should a result know the input that it was derived from? Or should the ResultSuite (which is also nongeneric) know the input that has been applied to all its functions? The information will certainly need to be &lt;em&gt;somewhere&lt;/em&gt; so that it can be output appropriately in the multiple input case.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;My main points of design focus around three areas:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Is it easy to pick up? The more flexible it is, with lots of options, the more daunting it may seem.&lt;/li&gt;    &lt;li&gt;Is it flexible enough to be useful in a variety of situations? I don&amp;#39;t know what users will want to benchmark - and I don&amp;#39;t build the right tool, it will be worthless to them.&lt;/li&gt;    &lt;li&gt;Is the resulting test code easy and brief enough to include in a forum post, with a link to the full program? Will readers understand it?&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;As you can see, these are aimed at three slightly different people: the first time test writer, the veteran test writer, and the first time test reader. Getting the balance between the three is tricky.&lt;/p&gt;  &lt;h3&gt;What&amp;#39;s next?&lt;/h3&gt;  &lt;p&gt;I haven&amp;#39;t started rewriting the framework yet, but will probably do so soon. This time I hope to do it in a rather more test-driven way, although of course the timing-specific elements will be tricky unless I start using a programmatic clock etc. I&amp;#39;d really like comments around this whole process:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Is this worth doing?&lt;/li&gt;    &lt;li&gt;Am I asking the right questions?&lt;/li&gt;    &lt;li&gt;Are my answers so far headed in the right direction?&lt;/li&gt;    &lt;li&gt;What else haven&amp;#39;t I thought of?&lt;/li&gt; &lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1668242" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Stack+Overflow/default.aspx">Stack Overflow</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Benchmarking/default.aspx">Benchmarking</category></item></channel></rss>