{"id":27393,"date":"2007-04-03T07:00:00","date_gmt":"2007-04-03T14:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/04\/03\/why-does-my-thread-pool-use-only-one-thread\/"},"modified":"2007-04-03T07:00:00","modified_gmt":"2007-04-03T14:00:00","slug":"why-does-my-thread-pool-use-only-one-thread","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070403-00\/?p=27393","title":{"rendered":"Why does my thread pool use only one thread?"},"content":{"rendered":"<p>\nThe thread pool is about reducing thread creating\/termination\noverhead by consolidating work that would normally go onto separate\nthreads into a small number of threads.\nIn a sense, you shouldn&#8217;t be surprised that the thread pool is using\nonly one thread; instead, you should be happy!\n<\/p>\n<blockquote CLASS=\"m\"><p>\nI switched to using the thread pool, and I&#8217;m finding that it&#8217;s\nusing only one thread.\nTo demonstrate this, I wrote a test program that fires off a bunch\nof &#8220;work items&#8221; into the thread pool via\n<code>QueueUserWorkItem<\/code>.\nEach work item does some intensive computations.\nWhat I&#8217;m seeing is that they are all running serially on a single\nthread instead of running in parallel.\nSince I have a dual-processor machine, this leaves half of\nthe computing capacity unutilized.\nIf I create a separate thread for each &#8220;work item&#8221;,\nthen I get (not surprising) multiple threads and 100% CPU utilization.\nWhy does my thread pool use only one thread?\n<\/p><\/blockquote>\n<p>\nThe purpose of the thread pool, as I noted above, was to reduce\nthe overhead of creating and terminating threads by running\nmultiple tasks on a thread.\nFor example, suppose you have three short tasks, say 1ms each.\nIf you put each one on its own thread, you have\n<\/p>\n<ul>\n<li>\n    Task1.CreateThread,\n    Task1.Run,\n    Task1.EndThread\n<\/li>\n<li>\n    Task2.CreateThread,\n    Task2.Run,\n    Task2.EndThread\n<\/li>\n<li>\n    Task3.CreateThread,\n    Task3.Run,\n    Task3.EndThread\n<\/li>\n<\/ul>\n<p>\nNow suppose, for the purpose of this discussion, that creating\nand terminating a thread take 1ms each.\nif you create a separate thread for each task, you&#8217;ve spent\n6ms on thread overhead and only 3ms doing actual work.\n<\/p>\n<p>\nWhat if we could run multiple tasks on a single thread?\nThat way, the cost of creating and terminating the thread\ncould be amortized over all the tasks.\n<\/p>\n<ul>\n<li>\n    ThreadPool.CreateThread,\n    Task1.Run,\n    Task2.Run,\n    Task3.Run,\n    ThreadPool.EndThread\n<\/li>\n<\/ul>\n<p>\nAh, now we have only 2ms of overhead for 3ms of work.\nNot great, but certainly better than what we had before.\nIf we can pack more tasks into the thread pool,\nthe fixed overhead of creating and terminating the thread\nbecomes proportionally less.\n<\/p>\n<p>\nThe thread pool is designed for handling a collection of\nbrief tasks, since those are the tasks that would best benefit\nfrom thread pooling.\nIf you had a task that ran for ten seconds, putting it on\nthe thread pool wouldn&#8217;t yield much in the way of savings;\nthat 2ms overhead you avoided is just noise compared to your\nten seconds of running time.\n(Last year, we saw\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/03\/14\/551140.aspx#551339\">\nanother case of a series of tasks ill-suited to thread pooling<\/a>.)\n<\/p>\n<p>\nAs an accommodation for people who will put the occasional\nlong-running task onto the thread pool (perhaps because it\nsimplifies the program logic by treating everything as a\nwork item), the thread pool allows you to give it a heads-up\nby\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/07\/22\/441785.aspx\">\npassing the <code>WT_EXECUTELONGFUNCTION<\/code> flag<\/a>.\nBut that&#8217;s not really what the thread pool is for.\nIt&#8217;s for quick-running tasks for which the overhead of creating\na separate thread would be disproportionate to the work\ndone by the task itself.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Because one thread is all it needs.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-27393","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Because one thread is all it needs.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27393","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=27393"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27393\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=27393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=27393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=27393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}