{"id":2263,"date":"2009-03-03T21:27:00","date_gmt":"2009-03-03T21:27:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2009\/03\/03\/whats-new-in-beta-1-for-the-coordination-data-structures\/"},"modified":"2009-03-03T21:27:00","modified_gmt":"2009-03-03T21:27:00","slug":"whats-new-in-beta-1-for-the-coordination-data-structures","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/whats-new-in-beta-1-for-the-coordination-data-structures\/","title":{"rendered":"What\u2019s new in Beta 1 for the coordination data structures?"},"content":{"rendered":"<p>We&#8217;re currently working on the Beta of .NET 4.0 (no dates to announce) and there are lots o\u2019 new stuff for the Parallel Extensions.\u00a0 We hope you\u2019re as excited about it as we are.\u00a0 Given that we have so much coming down the pipes, we decided to roll out posts on what\u2019s coming in digestible chunks.\u00a0 What\u2019s better to start with than the low-level infrastructure? In addition to the coordination data structures, you can expect posts on changes in the Task Parallel Library (TPL) as well as Parallel LINQ (PLINQ) and a few miscellaneous topics.<\/p>\n<h3>New Types<\/h3>\n<p>Since our last CTP in September \u201808, we\u2019ve added a few new types to add to your parallel-programming arsenal.<\/p>\n<p><b>ConcurrentBag&lt;T&gt;      <br><\/b>In short, ConcurrentBag&lt;T&gt; is a thread-safe, unordered collection of objects.\u00a0 Sounds a bit like a set, but unlike a set, ConcurrentBag&lt;T&gt; allows duplicates.\u00a0 So now you\u2019re thinking, what\u2019s so interesting about an unordered collection that allows duplicates?\u00a0 Truth be told, in a single-thread world, not very much.\u00a0 In a multi-threaded world, however, removing ordering restrictions allows us to do some pretty cool optimizations that makes for a really scalable and efficient type in certain situations.\u00a0 <\/p>\n<p>You can think of ConcurrentBag&lt;T&gt; as a thread-safe linked list of thread-safe double-ended queues (deques). Each thread that touches the bag has it\u2019s own deque to which it adds and removes items from the top. When any thread\u2019s deque is empty, it pulls from the <i>bottom<\/i> of another thread\u2019s non-empty deque.\u00a0 You can see why this is scalable and efficient: in many cases, there is no contention at all. Contention is only an issue when a thread does not have any items and is forced to \u201csteal\u201d items from another thread.\u00a0 It\u2019s worth noting that the add-to-the-top-steal-from-the-bottom approach plays nice with the cache: threads get to work on items in nice contiguous chunks. In fact, this type of work-stealing queue works so well that it\u2019s principally how the Thread Pool in .NET 4.0 load-balances work.\u00a0 <\/p>\n<p>Just to make it clear, ConcurrentBag&lt;T&gt; isn\u2019t <i>always<\/i> the fastest choice.\u00a0 Consider the single producer\/single consumer scenario: the producer would always steal from the consumer\u2019s deque \u2013 ConcurrentQueue&lt;T&gt; would be much more efficient. Scenarios in which threads both produce and consume values will benefit from ConcurrentBag&lt;T&gt; the most.<\/p>\n<p align=\"center\"><a href=\"https:\/\/blogs.msdn.com\/blogfiles\/pfxteam\/WindowsLiveWriter\/WhatsnewinBeta1forthecoordinationdatastr_CBB0\/concbag_2.gif\"><img decoding=\"async\" style=\"border-right-width: 0px;float: none;border-top-width: 0px;border-bottom-width: 0px;margin-left: auto;border-left-width: 0px;margin-right: auto\" title=\"concbag\" border=\"0\" alt=\"concbag\" width=\"318\" height=\"252\" src=\"\"><\/a><b><font size=\"2\"> Figure 1.\u00a0 How threads access elements in a ConcurrentBag&lt;T&gt;.<\/font><\/b><\/p>\n<p><b><\/b><\/p>\n<p><b>ConcurrentLinkedList&lt;T&gt; and ConcurrentLinkedListNode&lt;T&gt;      <br><\/b>ConcurrentLinkedList&lt;T&gt; is essentially a thread-safe version of LinkedList&lt;T&gt;.\u00a0 Of course there are some caveats, this <i>is <\/i>parallel programming we\u2019re talking about.\u00a0 \ud83d\ude42 Just inserting a value into a linked list becomes difficult in a multi-threaded world.\u00a0 Say you want to add items to a list in sorted order.\u00a0 With single-threaded linked lists, this is a simple as walking the list and finding the position where the left node is less than the value you want to insert and the right node is greater than or equal to that value.\u00a0 In a concurrent environment, between the time you\u2019ve found the location and actually added the value, another value could have been inserted in that place or one of the neighboring nodes removed.\u00a0 Thus, ConcurrentLinkedList&lt;T&gt; provides methods that support these tasks with atomic operations, like the TryInsertBetween method:<\/p>\n<pre class=\"csharpcode\">list.TryInsertBetween( (left, right) =&gt;     ((left.Value &lt; item) &amp;&amp; (right.Value &gt; item)), item);<\/pre>\n<p>.csharpcode, .csharpcode pre{\tfont-size: small;\tcolor: black;\tfont-family: consolas, &#8220;Courier New&#8221;, courier, monospace;\tbackground-color: #ffffff;\t\/*white-space: pre;*\/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {\tbackground-color: #f4f4f4;\twidth: 100%;\tmargin: 0em;}.csharpcode .lnum { color: #606060; }<\/p>\n<p>TryInsertBetween will walk the list and insert the value only when the supplied predicate returns true. It does all this atomically.\u00a0 If it fails, it returns false without changing the list.<\/p>\n<p style=\"margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><b>Partitioner&lt;T&gt; and OrderablePartitioner&lt;T&gt;       <br><\/b>When TPL or PLINQ consume a data structure, they do their best to load balance the elements between threads.\u00a0 Of course, TPL and PLINQ don\u2019t have detailed knowledge about the data sources, such as each structures internals, the values of the data, and the length of the data source \u2013 all of which are factors in execution time. The APIs simply see that a type implements IEnumerable&lt;T&gt; or IList&lt;T&gt; and start processing the elements based on enumeration or indexing.\u00a0 Often times, this means that significant performance gains are overlooked.\u00a0 Partitioners allow you to achieve these gains.<\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\" class=\"MsoNormal\"><span style=\"font-family: 'Times New Roman','serif';font-size: 12pt\" lang=\"EN\"><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\" class=\"MsoNormal\"><span style=\"font-family: 'Times New Roman','serif';font-size: 12pt\" lang=\"EN\"><font size=\"2\"><font face=\"Tahoma\">For example, say I\u2019ve created a thread-safe collection that protects elements with striped-locking (where elements 0, 3, and 6 are protected by lock A, 1, 4, and 7 by lock B and 2, 5, and 8 protected by lock C).\u00a0 If we just use the standard enumerator and the pattern will look like: acquire lock A, acquire lock B, acquire lock C, acquire lock A, acquire lock B, and so on.\u00a0 This is hardly an efficient manner to partition out elements, especially if other threads are playing around with the data structure.\u00a0 It would be much more efficient if we acquired each lock just once.\u00a0 In a perfect world, if Parallel.ForEach decided that three threads wanted to enumerate this hypothetical data structure, we\u2019d want to give all of the elements under lock A to one thread, the elements of lock B to another and the elements of lock C to the last, significantly reducing the amount of time spent acquiring locks and potentially waiting for locks to be given up.\u00a0 <\/font><\/font><\/span><\/p>\n<p><font size=\"2\"><font face=\"Tahoma\"><\/p>\n<p>\u00a0<\/p>\n<p>      <\/font><\/font><\/p>\n<p>\u00a0<\/p>\n<p><span style=\"font-family: 'Times New Roman','serif';font-size: 12pt\" lang=\"EN\"><\/span><\/p>\n<p><span style=\"font-family: 'Times New Roman','serif';font-size: 12pt\" lang=\"EN\"><font size=\"2\" face=\"Tahoma\">We\u2019ll be posting more detail on partitioners soon, but suffice it to say that Partitioner&lt;T&gt; allows you to create custom partitioning algorithms for any data source.\u00a0 OrderablePartitioner&lt;T&gt; does the same, but keeps account of each element\u2019s original index so the data can be reordered when necessary. Each of these abstract classes supports both static partitioning as well as dynamic partitioning. In addition to these extension points, we\u2019re providing a few out-of-the-box partitioners, but I\u2019ll keep you in suspense \u2013 check back for more detailed posts on partitioners soon!<\/font><\/span><\/p>\n<h3>Removed Types<\/h3>\n<p>In addition to adding new types, we also decided to cut one out.<\/p>\n<p><b>WriteOnce&lt;T&gt;     <br><\/b>In short, WriteOnce&lt;T&gt; was never really more than a simplification on top of Interlocked.CompareExchange and that doesn&#8217;t provide enough value at this point to warrant a new type in the .NET Framework. Farewell!<\/p>\n<h3>Refactors<\/h3>\n<p>There are lots of minor refactors and name changes coming in Beta 1 but there\u2019s only one major change for the coordination data structures that we should call out: LazyInit&lt;T&gt;.\u00a0 I won\u2019t list every name change an name space change but it\u2019s important to see how LazyInit&lt;T&gt; has been refactored. Originally, LazyInit&lt;T&gt; was a struct which gave it all the nuances that come with a value-type.\u00a0 We\u2019ve since refactored LazyInit&lt;T&gt; into four types: <\/p>\n<ul>\n<li>System.Lazy&lt;T&gt;: a class-based lazy initialization primitive that\u2019s safe to pass around. <\/li>\n<li>System.LazyVariable&lt;T&gt;: a struct-based lazy initialization primitive that has the value-type semantics (namely that you run the risk of re-initialization if you copy it or pass it to a method), but remains light-weight for situations where memory footprint is important. <\/li>\n<li>System.Threading.LazyInitializer: a set of static methods where memory footprint is <i>really <\/i>an issue. <\/li>\n<li>System.Threading.ThreadLocal&lt;T&gt;: originally a mode on LazyInit&lt;T&gt;, this is now its own type. <\/li>\n<\/ul>\n<p>In addition to the refactoring, Lazy&lt;T&gt; and LazyVariable&lt;T&gt; now have both thread-safe <i>and<\/i> non-thread-safe initialization modes for those that need the lazy initialization functionality without the overhead of synchronization.\u00a0 <\/p>\n<h3>Cancellation<\/h3>\n<p>In the Beta 1 release, you\u2019ll find a few types for a unified cancellation model intended to be used throughout the .NET framework.\u00a0 Cancellation holds enough merit to warrant a dedicated post on it so we\u2019ll be posting one soon.\u00a0 What\u2019s exciting is that we\u2019ve added cancellation support throughout TPL, PLINQ and the coordination data structures.\u00a0 For the data structures specifically, we\u2019ve added cancellation overloads to any of our APIs that may block, including: <\/p>\n<ul>\n<li>BlockingCollection&lt;T&gt;     \n<ul>\n<li>Add <\/li>\n<li>AddToAny <\/li>\n<li>GetConsumingEnumerable <\/li>\n<li>Take <\/li>\n<li>TakeFromAny <\/li>\n<li>TryAdd <\/li>\n<li>TryAddToAny <\/li>\n<li>TryTake <\/li>\n<li>TryTakeFromAny <\/li>\n<\/ul>\n<\/li>\n<li>Barrier.SignalAndWait <\/li>\n<li>CountdownEvent.Wait <\/li>\n<li>ManualResetEventSlim.Wait <\/li>\n<li>SemaphoreSlim.Wait <\/li>\n<\/ul>\n<h3>Misc. Changes<\/h3>\n<p>Again, there are too many minor changes to call out but just be aware that some types have moved to different namespaces and might have some APIs that were renamed.\u00a0 <\/p>\n<p>There are two API additions worth calling out, however:<\/p>\n<p><b>SpinWait.SpinUntil     <br><\/b>We realized that a lot of scenarios for SpinWait went something like this\u2026 Check a condition. If false, spin.\u00a0 Check a condition, if false, spin. Check a condition.\u00a0 If false spin\u2026 We decided to make it a tad easier by allowing you to pass a Func&lt;Boolean&gt; to SpinWait, causing it to spin until the condition was met or a timeout occurred. <\/p>\n<p><b>ConcurrentStack&lt;T&gt;.PushRange and ConcurrentStack&lt;T&gt;.PopRange     <br><\/b>We\u2019re all about squeezing out that last drop of performance and where we can, we do.\u00a0 Take ConcurrentStack&lt;T&gt; for example, which works on a single CompareAndSwap (CAS) operation if there is no contention.\u00a0 Many scenarios involve pushing or popping a series of items on or off the stack which typically results in looping through a collection, calling Push() on each item.\u00a0 This of course, results in N CAS operations and potentially a lot more if the stack is being contended on by multiple threads.\u00a0 Since we only need to do one CAS operation to update ConcurrentStack&lt;T&gt; anyway, we might as well build up a stack segment first and then push the whole segment onto the stack with a single CAS &#8211; reducing the number of potential retry CAS operations.\u00a0 Enter PushRange and PopRange, which do exactly that.<\/p>\n<p>Check back soon for what\u2019s new in TPL and PLINQ!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We&#8217;re currently working on the Beta of .NET 4.0 (no dates to announce) and there are lots o\u2019 new stuff for the Parallel Extensions.\u00a0 We hope you\u2019re as excited about it as we are.\u00a0 Given that we have so much coming down the pipes, we decided to roll out posts on what\u2019s coming in digestible [&hellip;]<\/p>\n","protected":false},"author":486,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[],"class_list":["post-2263","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam"],"acf":[],"blog_post_summary":"<p>We&#8217;re currently working on the Beta of .NET 4.0 (no dates to announce) and there are lots o\u2019 new stuff for the Parallel Extensions.\u00a0 We hope you\u2019re as excited about it as we are.\u00a0 Given that we have so much coming down the pipes, we decided to roll out posts on what\u2019s coming in digestible [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2263","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/486"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=2263"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2263\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=2263"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=2263"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=2263"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}