{"id":56067,"date":"2010-10-21T13:25:00","date_gmt":"2010-10-21T13:25:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2010\/10\/21\/new-feature-threadlocalt-values\/"},"modified":"2010-10-21T13:25:00","modified_gmt":"2010-10-21T13:25:00","slug":"new-feature-threadlocalt-values","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/new-feature-threadlocalt-values\/","title":{"rendered":"New Feature? :: ThreadLocal.Values"},"content":{"rendered":"<p class=\"MsoNormal\">We&rsquo;ve been considering adding a Values property to\nSystem.Threading.ThreadLocal&lt;T&gt;. &nbsp;Values\nwould return a collection of all current values from all threads (e.g. what\nyou&rsquo;d get if you evaluated Value from each thread).&nbsp; This would allow for easy aggregations, and\nin fact in our Parallel Extensions Extras we have a wrapper around\nThreadLocal&lt;T&gt; called <a href=\"https:\/\/blogs.msdn.com\/b\/pfxteam\/archive\/2010\/04\/12\/9990426.aspx\">ReducationVariable<\/a>&lt;T&gt;\nthat exists purely to provide this functionality.&nbsp; For example:<\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: 'courier new', courier\">var localResult = new ThreadLocal&lt;int&gt;(() =&gt; 0);<br>Parallel.For(0, N, i =&gt;<br>{<br>&nbsp;&nbsp; &nbsp;localResult.Value\n+= Compute(i);<br>});<\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: 'courier new', courier\">int result = localResult.Values.Sum();<\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: 'courier new', courier\"><br><\/span><\/p>\n<p class=\"MsoNormal\">If you&rsquo;re familiar with the Parallel Patterns Library (PPL)\nin Visual C++ 2010, this feature would make ThreadLocal&lt;T&gt; very similar in\ncapability to the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd492850.aspx\">combinable class<\/a>.<\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\">In .NET 4, it&rsquo;s already possible to do aggregations using\nthe thread-local data support that&rsquo;s built in to the parallel loops.<\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: 'courier new', courier\">Parallel.For(0,\nN,<br>&nbsp;&nbsp; &nbsp;() =&gt; 0,<br>&nbsp;&nbsp; &nbsp;(i, loopState, localResult) =&gt;<br>&nbsp;&nbsp; &nbsp;{<br>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return localResult\n+ Compute(i);<br>&nbsp;&nbsp; &nbsp;},<br>&nbsp;&nbsp; &nbsp;localResult =&gt; Interlocked.Add(ref result, localResult));<\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"font-family: 'courier new', courier\"><br><\/span><\/p>\n<p class=\"MsoNormal\">This approach of using Parallel.For has less overhead than\naccessing the ThreadLocal&lt;T&gt; instance on each iteration, which is one of\nthe reasons Parallel.For has the support built-in. &nbsp;However, there are some advantages to also\nhaving the ThreadLocal&lt;T&gt; approach available:<\/p>\n<ol>\n<li><strong>Fewer\ndelegates to understand<\/strong>.&nbsp; Wrapping\nyour head around three different delegates (and how data is passed between\nthem) in a single method call can be tough.&nbsp;\nIt may also be unintuitive that an interlocked operation is required for\nthe final step (though this approach has performance benefits, as each thread\ngets to perform its final reduction in parallel).<\/li>\n<li><strong>Certain\nscenarios may enjoy less overhead<\/strong>.<strong>&nbsp; <\/strong>There is potentially a subtle performance\nissue with the Parallel.For approach, depending on why the local support is\nbeing used.&nbsp; In an effort to be fair to\nother users of the ThreadPool, the Tasks that service a parallel loop will\nperiodically (every few hundred milliseconds) retire and reschedule replicas of\nthemselves.&nbsp; In this way, the threads\nthat were processing the loop&rsquo;s tasks get a breather to optionally process work\nin other AppDomains if the ThreadPool deems it necessary.&nbsp; The ThreadPool may also choose to remove the\nthread from active duty if it believes the active thread count is too high. Consequently,\nthe number of Tasks created to service the loop may be greater than the number\nof threads.&nbsp; In turn, the delegates that\ninitialize and finalize\/aggregate the local states will be executed more,\nbecause they are run for each new Task rather than each new Thread.&nbsp; Of course, this would only be an issue if the\ninitializer and finalizer delegates are very expensive, but it&rsquo;s worth noting\nthat the ThreadLocal&lt;T&gt; approach does not suffer from this.<\/li>\n<li><strong>Usable in\nplaces where built-in local support isn&rsquo;t available<\/strong>.&nbsp; You can do aggregations where we do not have\nbuilt-in thread-local data support.&nbsp; For\nexample, Parallel.Invoke does not provide local support.<\/li>\n<\/ol>\n<p class=\"MsoListParagraphCxSpMiddle\">\n<p class=\"MsoListParagraphCxSpLast\">\n<p class=\"MsoNormal\">Your input could help!&nbsp;\nIf you&rsquo;ve got a minute, feel free to answer the following questions\nand\/or provide other thoughts:<\/p>\n<ol>\n<li>Would you find writing aggregations easier with\nThreadLocal&lt;T&gt;.Values compared to using the support built in to the\nparallel loops?&nbsp; If so, does the\nconvenience make the feature worthwhile?<\/li>\n<li>Do you need\/want support for writing\naggregations outside of parallel loops?<\/li>\n<li>When you do aggregations, are the routines for\ninitializing and finalizing local state expensive?&nbsp; Examples would be great.<\/li>\n<\/ol>\n<p class=\"MsoListParagraphCxSpMiddle\">\n<p class=\"MsoListParagraphCxSpLast\">\n<p class=\"MsoNormal\">Thanks!<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We&rsquo;ve been considering adding a Values property to System.Threading.ThreadLocal&lt;T&gt;. &nbsp;Values would return a collection of all current values from all threads (e.g. what you&rsquo;d get if you evaluated Value from each thread).&nbsp; This would allow for easy aggregations, and in fact in our Parallel Extensions Extras we have a wrapper around ThreadLocal&lt;T&gt; called ReducationVariable&lt;T&gt; that [&hellip;]<\/p>\n","protected":false},"author":485,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7916,7921,7927,7909,7912],"class_list":["post-56067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-coordination-data-structures","tag-feedback-requested","tag-new-feature","tag-parallel-extensions","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>We&rsquo;ve been considering adding a Values property to System.Threading.ThreadLocal&lt;T&gt;. &nbsp;Values would return a collection of all current values from all threads (e.g. what you&rsquo;d get if you evaluated Value from each thread).&nbsp; This would allow for easy aggregations, and in fact in our Parallel Extensions Extras we have a wrapper around ThreadLocal&lt;T&gt; called ReducationVariable&lt;T&gt; that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56067","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\/485"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=56067"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56067\/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=56067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}