<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Eric Eilebrecht's blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/ericeil/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/ericeil/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:23:07 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>CLR 4.0 ThreadPool Improvements: Part 2 (sort of...)</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/clr-4-0-threadpool-improvements-part-2-sort-of</link>
      <pubDate>Wed, 01 Sep 2010 11:58:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2010/09/01/clr-4-0-threadpool-improvements-part-2-sort-of/</guid>
      <description><![CDATA[It's now been more than 16 months since I promised to post about the improvements we made in the...]]></description>
      <content:encoded><![CDATA[<p>It's now been more than 16 months since I <a href="https://blogs.msdn.com/b/ericeil/archive/2009/04/23/clr-4-0-threadpool-improvements-part-1.aspx">promised to post</a> about the improvements we made in the ThreadPool's concurrency control algorithm for CLR 4.&nbsp; Lesson: don't promise to write a series of articles unless you've got the time to do it! </p>
<p>Luckily,&nbsp;Erika Fuentes, who you may recognize from <a href="https://blogs.msdn.com/b/ericeil/archive/2009/06/01/threadpool-on-channel-9.aspx">our Channel 9 video</a>, has written an article on this topic for MSDN Magazine.&nbsp; Lesson: lazyness works!</p>
<p>If you'd like to understand more about how the ThreadPool works, please do check out Erika's excellent article, <a href="https://msdn.microsoft.com/en-us/magazine/ff960958.aspx">Throttling Concurrency in the CLR 4.0 ThreadPool</a>.&nbsp; If you have any questions, feel free to post them as comments here, and I'll do my best to answer.</p>]]></content:encoded>
    </item>
    <item>
      <title>ThreadPool on Channel 9</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/threadpool-on-channel-9</link>
      <pubDate>Mon, 01 Jun 2009 13:52:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2009/06/01/threadpool-on-channel-9/</guid>
      <description><![CDATA[Charles from&nbsp;Channel 9 stopped by my office a couple of weeks ago to chat with Erika Parsons...]]></description>
      <content:encoded><![CDATA[<P>Charles from&nbsp;<A href="https://channel9.msdn.com/" mce_href="https://channel9.msdn.com/">Channel 9</A> stopped by my office a couple of weeks ago to chat with Erika Parsons and I about the <A href="https://blogs.msdn.com/ericeil/archive/2009/04/23/clr-4-0-threadpool-improvements-part-1.aspx" mce_href="https://blogs.msdn.com/ericeil/archive/2009/04/23/clr-4-0-threadpool-improvements-part-1.aspx">ThreadPool work we're doing for&nbsp;.NET 4</A>.&nbsp; I learned something from this: understanding something, and explaining it in person, for the first time, in front of a camera, are two very different things.&nbsp;:)&nbsp; If you'd like to hear a little more about the .NET 4 ThreadPool, and have about 45 minutes to spare, <A href="https://channel9.msdn.com/shows/going+deep/erika-parsons-and-eric-eilebrecht--clr-4-inside-the-new-threadpool/" mce_href="https://channel9.msdn.com/shows/going+deep/erika-parsons-and-eric-eilebrecht--clr-4-inside-the-new-threadpool/">check out the video</A>.&nbsp; Then be sure to read a <A href="https://en.wikipedia.org/wiki/ABA_problem" mce_href="https://en.wikipedia.org/wiki/ABA_problem"><EM>correct</EM> explaination of the A-B-A problem</A>.</P>]]></content:encoded>
    </item>
    <item>
      <title>CLR 4.0 ThreadPool Improvements: Part 1</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/clr-4-0-threadpool-improvements-part-1</link>
      <pubDate>Thu, 23 Apr 2009 13:40:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2009/04/23/clr-4-0-threadpool-improvements-part-1/</guid>
      <description><![CDATA[This is the first in a series of posts about the improvements we are making to the CLR thread pool...]]></description>
      <content:encoded><![CDATA[<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">This is the first in a series of posts about the improvements we are making to the CLR thread pool for CLR 4.0 (which will ship with Visual Studio 2010).<span style="mso-spacerun: yes">&nbsp; </span>This post will cover changes to the queuing infrastructure in the thread pool, which aim to enable high-performance fine-grained parallelism via the Task Parallel Library.<span style="mso-spacerun: yes">&nbsp; </span>Future posts will cover the &ldquo;thread injection&rdquo; algorithm, and any other topics that readers would like to see.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">Please note that all the usual caveats apply here: I&rsquo;m discussing pre-release software, and all details are subject to change before final release.<span style="mso-spacerun: yes">&nbsp; </span>In fact, one goal of this post is to solicit feedback, so we can know what changes we <i style="mso-bidi-font-style: normal">need</i> to make before we ship. </span></span><span style="LINE-HEIGHT: 115%; FONT-FAMILY: Wingdings; FONT-SIZE: 10pt; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings">J</span></span><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">A thread pool basically has two functions:<span style="mso-spacerun: yes">&nbsp; </span>It maintains a queue (or queues) of work to be done, and a collection of threads which execute work from the queue(s).<span style="mso-spacerun: yes">&nbsp; </span>So designing a thread pool really comes down to a) finding ways to enqueue and dequeue work items very quickly (to keep the overhead of using the thread pool to a minimum) and b) developing an algorithm for choosing an optimal number of threads to service the queues.<span style="mso-spacerun: yes">&nbsp; </span>This post will cover part (a).</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">In all prior releases of the CLR, the thread pool exposed a single way to queue work: ThreadPool.QueueUserWorkItem (which I will abbreviate as QUWI from here on out).<span style="mso-spacerun: yes">&nbsp; </span>There are a couple of overloads of this method, and also a version called UnsafeQueueUserWorkItem, but these all amount to basically the same thing: you give us a delegate, and we stick it on a queue for later execution.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">(Really there are even more ways to queue work.<span style="mso-spacerun: yes">&nbsp; </span>As mentioned in my </span><a href="https://blogs.msdn.com/ericeil/archive/2008/06/20/windows-i-o-threads-vs-managed-i-o-threads.aspx"><span style="font-family: Calibri;">previous post</span></a><span style="font-family: Calibri;"> we really have <i style="mso-bidi-font-style: normal">two</i> pools of threads &ndash; the &ldquo;worker threads&rdquo; and the &ldquo;I/O threads.&rdquo;<span style="mso-spacerun: yes">&nbsp; </span>Work is queued to the I/O threads in response to the completion of asynchronous I/O, or manually via ThreadPool.UnsafeQueueNativeOverlapped.<span style="mso-spacerun: yes">&nbsp; </span>We currently do not plan any significant changes to the I/O pool for CLR 4.0, as our focus for this release is on enabling fine-grained computational parallelism.<span style="mso-spacerun: yes">&nbsp; </span>For the remainder of this post, we will only discuss the mechanisms behind the &ldquo;worker threads.&rdquo;)<o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">QUWI conveys basically zero information about each work item, aside from that it exists.<span style="mso-spacerun: yes">&nbsp; </span>This places some important constraints on the execution of these items.<span style="mso-spacerun: yes">&nbsp; </span>For example, the thread pool does not know whether individual work items are related or not, so it has to assume they are all completely independent, implying that we cannot reorder work to optimize its execution, as independent work items typically must be executed in FIFO order to ensure fairness.<span style="mso-spacerun: yes">&nbsp; </span>(Imagine each work item represents a request from a user - you would not want to keep earlier requests waiting while later requests are processed, as this would result in unacceptably long latency for the users who made their requests first).</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-size: small;"><span style="font-family: Calibri;">This means that we are basically forced to use a single FIFO queue for all work queued via QUWI.<span style="mso-spacerun: yes">&nbsp; </span>In prior versions of the CLR, this queue was a simple linked list, protected by a Monitor lock.<span style="mso-spacerun: yes">&nbsp; </span>This incurs some overhead: we must allocate nodes for the list (and pay the cost of the GC having to traverse the list each time a GC occurs), and we must pay the cost of acquiring that lock every time we enqueue or dequeue a work item.<span style="mso-spacerun: yes">&nbsp; </span></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">(Another aside: please do not take the above to mean that we make any guarantees about strict FIFO ordering of work item execution.<span style="mso-spacerun: yes">&nbsp; </span>In fact, we violate this &ldquo;rule&rdquo; already: since .NET 3.5, the CLR thread pool has maintained separate FIFO queues for each AppDomain in the process, and an additional independent FIFO queue for &ldquo;native&rdquo; work items such as those queued by a host (ASP.net being the prime user of this feature).<span style="mso-spacerun: yes">&nbsp; </span>We round-robin between these work queues, allowing each to execute work for some time before moving on to the next.<o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">This strategy is motivated by performance concerns, as it greatly reduces the number of transitions between AppDomains, which are fairly expensive.<span style="mso-spacerun: yes">&nbsp; </span>But it is designed to maintain fairness, which is the chief concern which we can never completely abandon.<span style="mso-spacerun: yes">&nbsp; </span>We may make further changes in the future which further deviate from the strict FIFO model, but we are unlikely to ever make QUWI really unfair, which, as we will see, is crucial to achieving good performance for fine-grained workloads.)<o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">This was fine for the kinds of workloads for which the thread pool was originally designed. These are relatively "coarse" workloads, where each work item represents a fairly large amount of work.<span style="mso-spacerun: yes">&nbsp; </span>The canonical example is an ASP.net web application, where each work item represents the generation of an entire web page.<span style="mso-spacerun: yes">&nbsp; </span>In such workloads, the work itself takes long enough that the overhead of allocating queue nodes and acquiring locks is barely noticeable.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-size: small;"><span style="font-family: Calibri;">However, in the new world of machines with rapidly increasing core counts, there is increased interest in more "fine grained" work.<span style="mso-spacerun: yes">&nbsp; </span>Where before the job of the thread pool was to take a large number of independent, coarse-grained, tasks and funnel them onto a few threads, we are increasingly being asked to execute many very small tasks representing tiny pieces of some larger operation.<span style="mso-spacerun: yes">&nbsp; </span></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Anyone who has tried executing such a workload on the existing CLR thread pool has probably found that it's not a simple matter of calling QUWI for each piece of the calculation; with such tiny work items, the overhead of enqueuing and dequeuing the work can be much greater than the work itself, resulting in slower execution than if we had just run the work on a single thread to begin with!<span style="mso-spacerun: yes">&nbsp; </span>It is possible to make this work, by &ldquo;batching&rdquo; work into a smaller number of calls to QUWI.<span style="mso-spacerun: yes">&nbsp; </span>There are many strategies for this, all of which are fairly complex in the general case.<span style="mso-spacerun: yes">&nbsp; </span>We would like to make this easy, but the current QUWI is insufficient for this goal.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">We can improve this situation in a couple of ways:<span style="mso-spacerun: yes">&nbsp; </span>we can implement a more efficient FIFO queue, and we can enhance the API to allow the user to give us more information, allowing us to turn to even more efficient queuing strategies.<span style="mso-spacerun: yes">&nbsp; </span>For CLR 4.0, we are doing both of these.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><b style="mso-bidi-font-weight: normal"><span style="font-size: small;"><span style="font-family: Calibri;">Faster FIFO<o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Recall that the overhead of the existing FIFO queue comes from the expense of allocating and traversing the data structure, and the cost of acquiring the lock on each enqueue and dequeue operation.<span style="mso-spacerun: yes">&nbsp; </span>For 4.0, we are switching to a lock-free data structure with much lower synchronization overhead.<span style="mso-spacerun: yes">&nbsp; </span>More importantly, this new queue is much friendlier to the GC; we still need to allocate a new object for each call to QUWI, but these objects are smaller, and are tracked in large &ldquo;chunks&rdquo; which are much easier for the GC to traverse than the simple linked list used previously.<span style="mso-spacerun: yes">&nbsp; </span>This new queue is virtually identical to System.Collections.Concurrent.ConcurrentQueue&lt;T&gt;, which is also new in 4.0.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Improving the performance of QUWI is nice, as it benefits existing applications which use the thread pool without requiring any changes to the application code.<span style="mso-spacerun: yes">&nbsp; </span>How much of a speedup you can expect will depend greatly on many factors, including your application&rsquo;s workload and the details of the particular hardware on which it executes, but for fine-grained workloads on multi-core hardware the speedup should be significant.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">However, we are still restricted in what we can do here &ndash; we still have very little information about the work we&rsquo;re executing, and so we still need to use the same basic strategy to execute it.<span style="mso-spacerun: yes">&nbsp; </span>We can trim overhead here and there, but QUWI will probably never be a great way to execute very fine-grained workloads.<span style="mso-spacerun: yes">&nbsp; </span>We need a new API.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><b style="mso-bidi-font-weight: normal"><span style="font-size: small;"><span style="font-family: Calibri;">The Task Parallel Library<o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">The Task Parallel Library (TPL) is a collection of new classes specifically designed to make it easier and more efficient to execute very fine-grained parallel workloads on modern hardware.<span style="mso-spacerun: yes">&nbsp; </span>TPL has been available separately as a </span><a href="https://blogs.msdn.com/somasegar/archive/2007/11/29/parallel-extensions-to-the-net-fx-ctp.aspx"><span style="font-family: Calibri; font-size: small;">CTP</span></a><span style="font-family: Calibri; font-size: small;"> for some time now, and was included in the </span><a href="https://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"><span style="font-family: Calibri; font-size: small;">Visual Studio 2010 CTP</span></a><span style="font-family: Calibri; font-size: small;">, but in those releases it was built on its own dedicated work scheduler.<span style="mso-spacerun: yes">&nbsp; </span>For Beta 1 of CLR 4.0, the default scheduler for TPL will be the CLR thread pool, which allows TPL-style workloads to &ldquo;play nice&rdquo; with existing, QUWI-based code, and allows us to reuse much of the underlying technology in the thread pool - in particular, the thread-injection algorithm, which we will discuss in a future post. </span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">I won&rsquo;t discuss all of the details of the TPL API, which better covered by </span><a href="https://blogs.msdn.com/pfxteam/"><span style="font-family: Calibri; font-size: small;">its authors</span></a><span style="font-family: Calibri; font-size: small;">. From the point of view of the performance of the thread pool, the important thing about TPL is that it is a much richer API than QUWI, giving the thread pool much more information about the work being executed.<span style="mso-spacerun: yes">&nbsp; </span>In particular, the new Task type exposes the notion of parent/child relationships, giving us some idea of the <i style="mso-bidi-font-style: normal">structure</i> of the overall computation being performed by the individual work items.<span style="mso-spacerun: yes">&nbsp; </span>Having this information opens up possibilities for much more efficient execution of these tasks.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">Even without parent/child relationships, Task is a major improvement over QUWI.<span style="mso-spacerun: yes">&nbsp; </span>QUWI returns nothing of use to the caller; it simply queues a delegate, and leaves it up to the implementation of that delegate to coordinate its activities with the rest of the application.<span style="mso-spacerun: yes">&nbsp; </span>QUWI provides no means of waiting for the completion of the work item, for handling exceptions, or getting the result of a computation.<span style="mso-spacerun: yes">&nbsp; </span>Task provides all of this in a very easy-to-use form, while adding very little overhead vs. QUWI.<span style="mso-spacerun: yes">&nbsp; </span><o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">The fact that Task has a Wait method is not just a convenience; it eliminates one of the most common problems people face when using QUWI.<span style="mso-spacerun: yes">&nbsp; </span>It is fairly common for one work item to need to wait for the execution of another work item to complete.<span style="mso-spacerun: yes">&nbsp; </span>If the second work item has not yet begun executing, it will be sitting in the queue waiting for a worker thread to pick it up.<span style="mso-spacerun: yes">&nbsp; </span>It is possible that there are no available worker threads &ndash; maybe they&rsquo;re all waiting for other work items to complete!<span style="mso-spacerun: yes">&nbsp; </span>This can cause deadlock in the worst case, and very slow execution in the best, as the thread pool may be slow to add more worker threads to pick up these work items.<span style="mso-spacerun: yes">&nbsp; </span>Task.Wait, on the other hand, knows it&rsquo;s waiting for another task, and is tightly integrated with the thread pool such that it is able to determine whether the task has started executing, and if not <i style="mso-bidi-font-style: normal">it executes it immediately, in-line on the current thread</i>.<span style="mso-spacerun: yes">&nbsp; </span>This greatly improves performance and eliminates the possibility of deadlock in this situation.<o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt 0.5in"><span style="LINE-HEIGHT: 115%; FONT-SIZE: 10pt"><span style="font-family: Calibri;">For new code, <b style="mso-bidi-font-weight: normal">Task is now the preferred way to queue work to the thread pool</b>.<o:p></o:p></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Top-level Tasks have no parent.<span style="mso-spacerun: yes">&nbsp; </span>These are Tasks created by non-thread-pool threads, or with certain options specified at Task-creation time.<span style="mso-spacerun: yes">&nbsp; </span>These tasks are queued to the same FIFO queue we use for QUWI, and thus benefit from the improvements we&rsquo;ve made there &ndash; but they are also subject to the same limitations.<span style="mso-spacerun: yes">&nbsp; </span>Tasks queued in this way are simply a better QUWI &ndash; but now the fun starts:<span style="mso-spacerun: yes">&nbsp; </span>A parent task can create child tasks.<span style="mso-spacerun: yes">&nbsp; </span>This happens whenever a Task creates another Task (unless it overrides this behavior).<span style="mso-spacerun: yes">&nbsp; </span>These children are implicitly treated as sub-tasks of the larger task.<span style="mso-spacerun: yes">&nbsp; </span>We assume that sub-tasks can be executed in any order &ndash; fairness is not necessary &ndash; because all that matters is that the overall operation be completed as fast as possible.<span style="mso-spacerun: yes">&nbsp; </span>This lets us throw those FIFO restrictions out the window, and opens up the possibility for much more efficient work scheduling strategies.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><b style="mso-bidi-font-weight: normal"><span style="font-size: small;"><span style="font-family: Calibri;">Work Stealing<o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Since a child task is just a piece of a larger task, we don&rsquo;t need to worry about execution order.<span style="mso-spacerun: yes">&nbsp; </span>We just need to execute these things quickly.<span style="mso-spacerun: yes">&nbsp; </span>One well-known strategy for fast execution of unordered work items is &ldquo;work stealing.&rdquo; </span><a href="https://www.bluebytesoftware.com/blog/2008/08/12/BuildingACustomThreadPoolSeriesPart2AWorkStealingQueue.aspx"><span style="font-size: small;"><span style="font-family: Calibri;"><span style="mso-spacerun: yes">&nbsp;</span>Joe Duffy</span></span></a><span style="font-family: Calibri; font-size: small;"> and </span><a href="https://www.danielmoth.com/Blog/2008/11/new-and-improved-clr-4-thread-pool.html"><span style="font-family: Calibri; font-size: small;">Daniel Moth</span></a><span style="font-family: Calibri; font-size: small;"> explain this very well; click on the links if you&rsquo;re interested. </span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">The most important aspect of work-stealing is that it enables very fast enqueue and dequeue in the typical case, often requiring no synchronization at all.<span style="mso-spacerun: yes">&nbsp; </span>This virtually eliminates a large part of the overhead of QUWI, when working with child tasks.<span style="mso-spacerun: yes">&nbsp; </span>We still do need to allocate memory for the Task itself, and for the work-stealing queue, but like the improvements to the FIFO queue these data structures have been optimized for good GC performance.<span style="mso-spacerun: yes">&nbsp; </span>Parent tasks are fast; child tasks are much faster.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">There are still some limitations to how quickly tasks can be executed.<span style="mso-spacerun: yes">&nbsp; </span>If all tasks are top-level (non-child) tasks, they are subject to the FIFO ordering constraints of QUWI (albeit with much richer functionality).<span style="mso-spacerun: yes">&nbsp; </span>And even with work-stealing, we need to allocate and queue Task instances for every work item.<span style="mso-spacerun: yes">&nbsp; </span>To get even better performance, we need even more information about the work.<span style="mso-spacerun: yes">&nbsp; </span>Which brings us to&hellip;</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><b style="mso-bidi-font-weight: normal"><span style="font-family: Calibri; font-size: small;">Parallel.For and PLINQ</span></b></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">While not, strictly speaking, features of the CLR thread pool, the methods of the new Parallel class and PLINQ are critical new features of the public concurrency APIs in CLR 4.0.<span style="mso-spacerun: yes">&nbsp; </span>In fine-grained parallel applications, it is very common to need to execute the same code, over and over, with different data inputs.<span style="mso-spacerun: yes">&nbsp; </span>With QUWI or Task, this means allocating and queuing separate workitems for each input.<span style="mso-spacerun: yes">&nbsp; </span>The thread pool infrastructure does not know that all of these work items do the same thing, so it literally has to execute them, one at a time, as if they were completely different tasks.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Parallel.For, Parallel.ForEach, and PLINQ, provide a better way.<span style="mso-spacerun: yes">&nbsp; </span>These are essentially different ways of expressing the same thing:<span style="mso-spacerun: yes">&nbsp; </span>here is some code that needs to execute N times, as quickly as possible.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-size: small;"><span style="font-family: Calibri;">Just as with the parent/child relationships that Task provides, this extra information enables more aggressive optimization.<span style="mso-spacerun: yes">&nbsp; </span>These &ldquo;parallel loops&rdquo; do not need to be broken down into separate work items for each loop iteration.<span style="mso-spacerun: yes">&nbsp; </span>All that is needed is to break them into enough chunks (&ldquo;partitions&rdquo;) that they can be efficiently load-balanced across all available machine resources.<span style="mso-spacerun: yes">&nbsp; </span>A typical scenario might be that 1,000,000 iterations need to be broken into, say, four work items.<span style="mso-spacerun: yes">&nbsp; </span></span></span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">There is, of course, some overhead introduced by the need to dynamically partition the data (done automatically by the framework). <span style="mso-spacerun: yes">&nbsp;</span>But this pales in comparison to the savings of not having to allocate, queue, and dequeue millions (or more!) work items. <span style="mso-spacerun: yes">&nbsp;</span>In a test I just tried, for a particular work load on one of my machines, Parallel.For executed more than 300 times as fast as the equivalent na&iuml;ve usage of QUWI.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><b style="mso-bidi-font-weight: normal"><span style="font-size: small;"><span style="font-family: Calibri;">Where do we go from here?<o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">By now you&rsquo;ve probably got the general theme: the more information we have about a workload, the faster we are likely to be able to execute it.<span style="mso-spacerun: yes">&nbsp; </span>I expect this theme to continue in future releases.<span style="mso-spacerun: yes">&nbsp; </span>The challenge is to find new ways to easily express (or automatically extract) useful information about parallel workloads, which can be used by the thread pool (or higher-level abstractions like PLINQ) to enable more optimizations.<span style="mso-spacerun: yes">&nbsp; </span>I think this is going to be an interesting space to watch for quite some time.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">In the meantime, please try out the new mechanisms we are providing in Visual Studio 2010 Beta 1. <span style="mso-spacerun: yes">&nbsp;</span>Try it with the kinds of workloads you expect to use in production; one of the biggest challenges we face is that we can really only guess at what developers will do with this stuff in the real world, so feedback from our customers is extremely important to ensure that these new mechanisms will meet your needs in the final product.</span></p>
<p class="MsoNormal" style="MARGIN: 0in 0in 10pt"><span style="font-family: Calibri; font-size: small;">Feel free to post any questions you may have in the comments for this post; I&rsquo;ll try to answer what I can.<span style="mso-spacerun: yes">&nbsp; </span>My next post will cover the thread pool&rsquo;s &ldquo;thread injection&rdquo; algorithm, which is how we determine how many threads should be servicing the various queues I&rsquo;ve discussed here.<span style="mso-spacerun: yes">&nbsp; </span>If there&rsquo;s something else you&rsquo;d like me to cover, please let me know.</span></p>]]></content:encoded>
    </item>
    <item>
      <title>CLR 4.0: Parallel Extensions and the CLR ThreadPool</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/clr-4-0-parallel-extensions-and-the-clr-threadpool</link>
      <pubDate>Fri, 07 Nov 2008 15:03:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/11/07/clr-4-0-parallel-extensions-and-the-clr-threadpool/</guid>
      <description><![CDATA[It's been a while since I've posted; for the past several months I've been working on deep changes...]]></description>
      <content:encoded><![CDATA[<P>It's been a while since I've posted; for the past several months I've been working on deep changes in the CLR ThreadPool to support the Parallel Extensions to the .NET Framework.</P>
<P>I hope to say a few things about the changes we're making in the CLR to support this new programming model over the coming months.&nbsp; But for now I encourage everyone to watch <A class="" href="https://channel9.msdn.com/pdc2008/TL26/" mce_href="https://channel9.msdn.com/pdc2008/TL26/">Daniel Moth's excellent PDC presentation</A> on this subject.&nbsp; He does a fantastic job of outlining what we're doing, and why it matters to you.</P>
<P>And a quick note about the CTP release of the CLR that was distributed at PDC: this does <EM>not</EM> include the new ThreadPool.&nbsp; The Parallel Extensions are running on their own task scheduler in this release.&nbsp; However, as Daniel mentions we do intend to ship CLR 4.0 with the Parallel Extensions deeply integrated with a much-improved CLR thread pool.&nbsp; Stay tuned!</P>]]></content:encoded>
    </item>
    <item>
      <title>Windows I/O threads vs. managed I/O threads</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/windows-io-threads-vs-managed-io-threads</link>
      <pubDate>Fri, 20 Jun 2008 12:41:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/06/20/windows-io-threads-vs-managed-io-threads/</guid>
      <description><![CDATA[A question recently came up on an internal discussion forum, which I'll paraphrase:&nbsp; The...]]></description>
      <content:encoded><![CDATA[<P>A question recently came up on an internal discussion forum, which I'll paraphrase:&nbsp; The Windows QueueUserWorkItem API has an option to queue to an I/O thread.&nbsp; Why doesn't the managed ThreadPool.QueueUserWorkItem support this option?</P>
<P>First, some background: 
<P>In the Windows thread pool (the <A href="https://msdn.microsoft.com/en-us/library/ms686756(VS.85).aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/ms686756(VS.85).aspx">old one</A>, not the <A href="https://msdn.microsoft.com/en-us/library/ms686760.aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/ms686760.aspx">new Vista thread pool</A>), an "I/O thread" is one that processes APCs (<A href="https://msdn.microsoft.com/en-us/library/ms681951.aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/ms681951.aspx">Asynchronous Procedure Calls</A>) queued by other threads, or by I/O initiated from the I/O threads.&nbsp; One example of an I/O functions that completes via APCs is <A href="https://msdn.microsoft.com/en-us/library/aa365468(VS.85).aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/aa365468(VS.85).aspx">ReadFileEx</A>.&nbsp; The "non-I/O" threads get their work from a completion port, either as a result of QueueUserWorkItem, or I/O initiated on a handle bound to the threadpool with BinIoCompletionCallback.&nbsp; So they are both geared toward processing I/O completions, but they just use different mechanisms. 
<P>In the managed ThreadPool, we use the terms "worker thread" and "I/O thread."&nbsp; In our case, an I/O thread is one that waits on a completion port; i.e., it's exactly equivalent to Windows' <I>non-I/O thread</I>.&nbsp; How confusing!&nbsp; Our "worker threads" wait on a simple user-space work queue, and never enter an alertable state (unless user code does so), and so explicitly do <I>not</I> process APCs.&nbsp; Managed "worker threads" have no equivalent in the Windows thread pool, just as Windows "I/O threads" have no managed equivalent. 
<P>The managed <A href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem.aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem.aspx">QueueUserWorkItem</A> queues work to the "worker threads" only.&nbsp; <A href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.unsafequeuenativeoverlapped.aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.unsafequeuenativeoverlapped.aspx">UnsafeQueueNativeOverlapped</A> queues to the I/O threads, as do completions for asynchronous I/O performed on kernel objects that have been bound to the ThreadPool via <A href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.bindhandle.aspx" target=_blank mce_href="https://msdn.microsoft.com/en-us/library/system.threading.threadpool.bindhandle.aspx">BindHandle</A>. 
<P>Why don't we support APCs as a completion mechanism?&nbsp; APCs are really not a good general-purpose completion mechanism for user code.&nbsp; Managing the reentrancy introduced by APCs is nearly impossible; any time you block on a lock, for example, some arbitrary I/O completion might take over your thread.&nbsp; It might try to acquire locks of its own, which may introduce lock ordering problems and thus deadlock.&nbsp; Preventing this requires meticulous design, and the ability to make sure that someone else's code will never run during your alertable wait, and vice-versa.&nbsp; This greatly limits the usefulness of APCs. 
<P>And APCs don't scale well, except in certain very constrained scenarios, because there's no load-balancing of completions across threads; all I/O initiated by a given thread always completes with an APC queued to that same thread.&nbsp; You can, of course, implement your own load balancing, by using the APC to notify another thread of the completion, but you'll never do better in user-space than the kernel does with completion ports.&nbsp; So we provide a rich async I/O infrastructure based on completion ports, and nothing else. 
<P>The real question to answer, then, is: why does Windows allow this option in the first place?&nbsp; I would guess that this is because there is a lot of unmanaged code out there that uses APCs, so the unmanaged thread pool needs to support APCs in order to support running that large body of code on the thread pool.&nbsp; This doesn't apply to managed code; when the managed thread pool was first introduced there <EM>was no managed code in existence</EM>, so there was no backward-compatibility requirement to support APCs.</P>]]></content:encoded>
    </item>
    <item>
      <title>When does it make sense to use Win32 Fibers?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/when-does-it-make-sense-to-use-win32-fibers</link>
      <pubDate>Sun, 18 May 2008 11:13:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/05/18/when-does-it-make-sense-to-use-win32-fibers/</guid>
      <description><![CDATA[This has been discussed fairly frequently on the Web.&nbsp;
&nbsp;
Chris Brumme discusses this...]]></description>
      <content:encoded><![CDATA[<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3>This has been discussed fairly frequently on the Web.&nbsp;</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3>Chris Brumme discusses this here: </FONT><A href="https://blogs.msdn.com/cbrumme/archive/2003/04/15/51351.aspx"><FONT face=Calibri color=#800080 size=3>https://blogs.msdn.com/cbrumme/archive/2003/04/15/51351.aspx</FONT></A><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>Raymond Chen discusses this here:<SPAN style="mso-spacerun: yes">&nbsp; </SPAN></FONT></FONT><A href="https://blogs.msdn.com/oldnewthing/archive/2004/12/31/344799.aspx"><FONT face=Calibri color=#800080 size=3>https://blogs.msdn.com/oldnewthing/archive/2004/12/31/344799.aspx</FONT></A><FONT size=3><FONT face=Calibri>.<SPAN style="mso-spacerun: yes">&nbsp;</SPAN><SPAN style="mso-spacerun: yes"> </SPAN><o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3>There’s some discussion about the pros and cons of Fibers in SQL Server here: </FONT><A href="https://msdn.microsoft.com/en-us/library/aa175385.aspx"><FONT face=Calibri color=#800080 size=3>https://msdn.microsoft.com/en-us/library/aa175385.aspx</FONT></A><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3></FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri></FONT></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3>Those are just the first three relevant links from a simple search.&nbsp; But still, the subject comes up.&nbsp;&nbsp;</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri></FONT></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3>Most people think of threads vs. fibers in terms of the "expense" of each option.&nbsp; Fibers are often thought to be "cheaper" than threads (they're often referred to a "light-weight threads,") and are thought to perform better, or at least enable your app to do things to make it perform better.&nbsp; So what are the expenses involved here?</FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri size=3></FONT></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>For most apps, the most important expense of threads is the physical address space consumed by the stack.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Fibers don’t fix this; they carry just as much stack as a thread.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>Another expense of threads is that there is overhead to preemptive scheduling.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If you have more threads than CPUs, and they routinely use up all of their scheduling quanta, you have to pay the expense of the kernel periodically forcing a (possibly unnecessary) context switch.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This is a fairly rare problem for real apps, which almost never use their full quanta.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Usually an app has blocked on some kernel object, waiting for input from the user, <SPAN style="mso-spacerun: yes">&nbsp;</SPAN>the network, etc., long before the full quantum is used.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>And even if preemption does occur, it’s rarely the most significant expense an app incurs.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>If preemptive context switches are your biggest problem, the <I style="mso-bidi-font-style: normal">only</I> solution is to reduce the number of threads.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Fibers don’t solve that problem.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>However, reducing the number of threads introduces a new problem: you’ve still got the same amount of work to do, and now it’s up to you to multiplex all that work onto just a few threads.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>What fibers actually do (try to) solve is the problem of manually multiplexing lots of work onto a few threads.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>There are lots of ways to do this – asynchronous I/O being the prime example – but fibers try to make it really <I style="mso-bidi-font-style: normal">easy</I> by letting you keep your stack, so you can just write code the way you’re used to.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>Another common use of fibers is to implement <A class="" href="https://en.wikipedia.org/wiki/Coroutine" mce_href="https://en.wikipedia.org/wiki/Coroutine">coroutines</A>.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This is what Raymond Chen’s doing in his Enumerator example.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The idea here, again, is to make switching contexts easier by allowing you to do everything on the stack.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>But here there’s no pretense of a performance benefit; it’s quite obvious to everyone that allocating two or more 1MB stacks, and switching between them every few instructions, is going to suck, perf-wise.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>It’s just (supposed to be) easier to write code this way than the alternatives (allocating everything on the heap, splitting your logic across lots of methods, etc.).<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>So really fibers aren’t about performance at all, but about making manual context-switching easier.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>The downside of fibers is that they’re not a general-purpose mechanism like threads.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Any code that depends on thread-local storage (which is almost all code that does anything) doesn’t work with fibers.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>By going with fibers, you’re taking a lot of matters into your own hands; this is obvious in the case of scheduling, but it’s not so obvious that you’re also taking responsibility for most of what your language’s runtime library does, or vast swaths of Win32, etc.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><A class="" href="https://blogs.msdn.com/dinoviehland/archive/2005/09/15/469642.aspx" mce_href="https://blogs.msdn.com/dinoviehland/archive/2005/09/15/469642.aspx">You also can’t write managed code.</A><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>And you’ll never be able to call out to 3<SUP>rd</SUP> party code.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>So in exchange for easy context-switching, you get increased memory usage, and you lose the ability to use virtually any basic software building block ever written.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT size=3><FONT face=Calibri>For something like Microsoft SQL Server, which is one of the most highly-optimized apps on the planet, and which pretty much lives in its own world where memory is “cheap” and library code is suspect anyway, it probably made sense to go with fibers to help reduce context-switch overhead without having to completely re-write SQL Server.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>For almost literally everyone else, it just doesn’t make sense.<o:p></o:p></FONT></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><o:p><FONT face=Calibri size=3>&nbsp;</FONT></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><FONT size=3><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri>And if all you want is coroutines, ask your favorite language vender to provide proper support for them. </FONT></SPAN><SPAN style="COLOR: #1f497d; FONT-FAMILY: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2; mso-char-type: symbol; mso-symbol-font-family: Wingdings"><SPAN style="mso-char-type: symbol; mso-symbol-font-family: Wingdings">J</SPAN></SPAN><SPAN style="COLOR: #1f497d; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-themecolor: dark2"><FONT face=Calibri><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>C# has iterators, which beat the pants off of Raymond’s enumeration example; that’s a good start, but iterators are awkward for anything other than, well, enumerating things.<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;</SPAN></FONT></SPAN></FONT>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>ThreadPool changes in .NET 3.5 SP1 Beta</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/threadpool-changes-in-net-3-5-sp1-beta</link>
      <pubDate>Mon, 12 May 2008 15:22:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/05/12/threadpool-changes-in-net-3-5-sp1-beta/</guid>
      <description><![CDATA[.NET&nbsp;3.5 SP1 (A.K.A. CLR 2.0 SP2) is now available as a Beta release.
This beta release has...]]></description>
      <content:encoded><![CDATA[<P><A class="" href="https://blogs.msdn.com/somasegar/archive/2008/05/12/visual-studio-2008-and-net-fx-3-5-sp1-beta-available-now.aspx" mce_href="https://blogs.msdn.com/somasegar/archive/2008/05/12/visual-studio-2008-and-net-fx-3-5-sp1-beta-available-now.aspx">.NET&nbsp;3.5 SP1 (A.K.A. CLR 2.0 SP2) is now available as a Beta release.</A></P>
<P>This beta release has the fix for the ThreadPool ramp-up issue discussed <A class="" href="https://blogs.msdn.com/ericeil/archive/2008/03/14/threadpool-bug-in-clr-2-0-sp1.aspx" mce_href="https://blogs.msdn.com/ericeil/archive/2008/03/14/threadpool-bug-in-clr-2-0-sp1.aspx">here</A> and <A class="" href="https://www.michaelckennedy.net/blog/PermaLink,guid,708ee9c0-a1fd-46e5-8fa0-b1894ad6ce0f.aspx" mce_href="https://www.michaelckennedy.net/blog/PermaLink,guid,708ee9c0-a1fd-46e5-8fa0-b1894ad6ce0f.aspx">here</A>.&nbsp; It also has some other improvements to the ThreadPool's thread creation algorithm that can dramatically improve performance in some situations.</P>
<P>The "thread injection" algorithm in the ThreadPool is a tricky beast.&nbsp; There's simply no perfect solution to the problem - so every change is a complex balancing act between&nbsp;improving performance for a specific customer scenario&nbsp;on the one hand, and not creating more problems for other customers on the other.</P>
<P>We've tried to make these changes as carefully as possible, running them through all the threadpool scenario tests we've accumulated over the years.&nbsp; But we can't possibly test every real-world workload - we don't even know about them all! -&nbsp;and we necessarily have to depend on things like beta releases to find the problems our tests will never find.</P>
<P>If you have code that uses the thread pool, I encourage you to download this beta and try it out.&nbsp; Feel free to leave a comment here about any problems you might find, or you can use the official <A class="" href="https://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=2136&amp;SiteID=1" mce_href="https://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=2136&amp;SiteID=1">discussion forum</A>&nbsp;and <A class="" href="https://connect.microsoft.com/VisualStudio" mce_href="https://connect.microsoft.com/VisualStudio">feedback center</A>&nbsp;for the beta.&nbsp; </P>
<P>And if you have any suggestions for future improvements,&nbsp;and especially if you have examples&nbsp;of workloads that the current ThreadPool does not&nbsp;handle well, please let us know.&nbsp; </P>
<P>I look forward to any feedback you might have.</P>]]></content:encoded>
    </item>
    <item>
      <title>ThreadPool bug in CLR 2.0 SP1</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/threadpool-bug-in-clr-2-0-sp1</link>
      <pubDate>Fri, 14 Mar 2008 11:13:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/03/14/threadpool-bug-in-clr-2-0-sp1/</guid>
      <description><![CDATA[Shortly after the release of CLR 2.0 SP1 (a.k.a. Orcas or .NET 3.5), several customers noticed some...]]></description>
      <content:encoded><![CDATA[<P>Shortly after the release of CLR 2.0 SP1 (a.k.a. Orcas or .NET 3.5), several customers noticed some very odd behavior in the ThreadPool.&nbsp; The ThreadPool is supposed to create threads as fast as possible, up to the current setting for MinThreads - but it turns out that if you queue workitems very quickly (like in a tight loop that just calls QueueUserWorkitem), the pool will expand very slowly - we'll only create one thread every half second (which is the normal behavior once we've reached MinThreads).</P>
<P>Michael C. Kennedy's blog has <A class="" href="https://www.michaelckennedy.net/blog/PermaLink,guid,708ee9c0-a1fd-46e5-8fa0-b1894ad6ce0f.aspx" mce_href="https://www.michaelckennedy.net/blog/PermaLink,guid,708ee9c0-a1fd-46e5-8fa0-b1894ad6ce0f.aspx">sample code and some perfmon graphs</A> demonstrating this behavior.&nbsp; He also posted <A class="" href="https://www.michaelckennedy.net/blog/PermaLink,guid,f57cf127-7bf7-445e-bef4-14c3598f92eb.aspx" mce_href="https://www.michaelckennedy.net/blog/PermaLink,guid,f57cf127-7bf7-445e-bef4-14c3598f92eb.aspx">our suggested workaround</A>, which unfortunately boils down to "don't queue the work items so quickly."&nbsp; </P>
<P>We plan to fix this in CLR 2.0 SP2 (i.e., .NET 3.5 SP1).&nbsp; In the meantime, if you should encounter this, please try the workaround.</P>]]></content:encoded>
    </item>
    <item>
      <title>When should you call RegisteredWaitHandle.Unregister?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/when-should-you-call-registeredwaithandle-unregister</link>
      <pubDate>Thu, 13 Mar 2008 20:05:00 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2008/03/13/when-should-you-call-registeredwaithandle-unregister/</guid>
      <description><![CDATA[The managed ThreadPool provides a way to asynchronously wait for WaitHandles, via...]]></description>
      <content:encoded><![CDATA[<P>The managed ThreadPool provides a way to asynchronously wait for WaitHandles, via ThreadPool.RegisterWaitForSingleObject. This method returns a new instance of RegisteredWaitHandle, which has a single method: Unregister.&nbsp; It's obvious from the name that this will cancel a pending wait operation.&nbsp; What's not obvious is that even after a registered wait has completed, you should still call Unregister.</P>
<P>The reason is that RegisteredWaitHandle holds a reference to your WaitHandle, and holds a refcount on the underlying SafeHandle.&nbsp; If you don't call Unregister, then RegisteredWaitHandle will have to run its finalizer sometime later, before it can release the WaitHandle.&nbsp; Calling Unregister prevents the finalizer from running (which helps perf), and may get your handle closed faster.</P>
<P>RegisteredWaitHandle really, really should implement IDisposable.</P>]]></content:encoded>
    </item>
    <item>
      <title>Which managed memory model?</title>
      <link>https://docs.microsoft.com/archive/blogs/ericeil/which-managed-memory-model</link>
      <pubDate>Mon, 26 Nov 2007 17:26:44 GMT</pubDate>
      <dc:creator><![CDATA[Eric Eilebrecht - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/ericeil/2007/11/26/which-managed-memory-model/</guid>
      <description><![CDATA[In this article, Vance Morrison describes some of the issues involved in writing managed...]]></description>
      <content:encoded><![CDATA[<p>In <a href="https://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/" target="_blank">this article</a>, Vance Morrison describes some of the issues involved in writing managed multithreaded code that avoids the use of locks.&nbsp; In particular, he discusses the impact of memory models on lock-free (or low-lock) programming.</p> <p>For managed code running on the CLR, there are two models that matter:</p> <ol> <li>The ECMA CLI memory model</li> <li>The Microsoft CLR memory model</li></ol> <p>The ECMA model is very "weak," meaning that there are many possibilities for reordering of memory operations.&nbsp; The CLR model incorporates the ECMA model, but strengthens it with additional rules that prevent reorderings. <a href="https://blogs.msdn.com/cbrumme/archive/2003/05/17/51445.aspx" target="_blank">According to Chris Brumme</a>, the CLR memory model was strengthened because it was thought that a stronger model was easer to code to.&nbsp; </p> <p>So, when you're writing your own managed code, you should code to the strong CLR model, to make your life easier, right?&nbsp; I'm not sure.</p> <p>The process of writing correct lock-free code is inherently difficult.&nbsp; You have to think very carefully about every single memory operation in your algorithm, and how each might interact with operations on other threads.&nbsp; You must meticulously identify the required orderings.&nbsp; Then you must consult the rules of the underlying memory model to find a way to enforce each ordering requirement.</p> <p>In a weak memory model, such as the ECMA standard, most ordering requirements will not be automatically satisfied by the rules of the model; you will have to do something explicit (insert a memory barrier, mark a variable as volatile, etc) to enforce your requirements.&nbsp; In a strong model, many requirements <em>will</em> be automatically satisfied - but some will not, and you still need to think about each one and make a decision about what needs to be done (or not done).</p> <p>In my experience, programming to a strong model is not appreciably easier than a weak model.&nbsp; If anything, it's a bit harder, because there are so many more rules to keep in mind.&nbsp; Add to that the fact that the CLR model is not standardized, and is not portable to other CLI implementations (such as our own Compact Framework), and it's hard for me to see why anyone would want to target this model.</p> <p><strong>So what <em>is</em> the value of the CLR memory model?</strong></p> <p>The key is in the statement above, that "many requirements will be automatically satisfied."&nbsp; If, in the course of your analysis, you should happen to miss something (don't worry, it happens to everybody), you have a chance of being "saved" by the underlying strong memory model, and your code will run correctly. The CLR memory model acts as a sort of "safety net," just in case you make a mistake.</p> <p>In my opinion, this is a good thing to have.&nbsp; Lock-free/low-lock programming is so hard to get right, that it's good to know that the runtime may be able to save me from a mistake.</p> <p>My advice: code to the ECMA model for portability, and take comfort in the fact that you may be able to get away with some mistakes.</p>]]></content:encoded>
    </item>
  </channel>
</rss>