Home
%3CLINGO-SUB%20id%3D%22lingo-sub-357985%22%20slang%3D%22en-US%22%3EModifying%20the%20.NET%20CLR%20ThreadPool%20Settings%20for%20ASP.NET%204.x%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-357985%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%20style%3D%22display%3A%20inline%20!important%3B%20float%3A%20none%3B%20background-color%3A%20%23ffffff%3B%20color%3A%20%23333333%3B%20cursor%3A%20text%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20font-weight%3A%20300%3B%20letter-spacing%3A%20normal%3B%20line-height%3A%201.7142%3B%20orphans%3A%202%3B%20text-align%3A%20left%3B%20text-decoration%3A%20none%3B%20text-indent%3A%200px%3B%20text-transform%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20white-space%3A%20normal%3B%20word-spacing%3A%200px%3B%22%3EOne%20common%20problem%20we%20see%20is%20the%20blocking%20of%20.NET%20ThreadPool%20threads.%20This%20blocking%20can%20lead%20to%20ThreadPool%20thread%20starvation%2C%20and%20sometimes%20even%20deadlocks.%20%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%3CSPAN%20style%3D%22display%3A%20inline%20!important%3B%20float%3A%20none%3B%20background-color%3A%20%23ffffff%3B%20color%3A%20%23333333%3B%20cursor%3A%20text%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20font-weight%3A%20300%3B%20letter-spacing%3A%20normal%3B%20line-height%3A%201.7142%3B%20orphans%3A%202%3B%20text-align%3A%20left%3B%20text-decoration%3A%20none%3B%20text-indent%3A%200px%3B%20text-transform%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20white-space%3A%20normal%3B%20word-spacing%3A%200px%3B%22%3EThis%20is%20especially%20true%20as%20of%20late%20with%20more%20and%20more%20folks%20using%20asynchronous%20code%2C%20and%20trying%20to%20convert%20existing%2C%20synchronous%20methods%20into%20async%2C%20but%20leaving%20parts%20of%20the%20code%20sync.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%3CSPAN%20style%3D%22display%3A%20inline%20!important%3B%20float%3A%20none%3B%20background-color%3A%20%23ffffff%3B%20color%3A%20%23333333%3B%20cursor%3A%20text%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20font-weight%3A%20300%3B%20letter-spacing%3A%20normal%3B%20line-height%3A%201.7142%3B%20orphans%3A%202%3B%20text-align%3A%20left%3B%20text-decoration%3A%20none%3B%20text-indent%3A%200px%3B%20text-transform%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20white-space%3A%20normal%3B%20word-spacing%3A%200px%3B%22%3EI%20don't%20go%20into%20the%20above%20scenarios%20in%20this%20post%3B%20but%2C%20some%20folks%20want%20to%20change%20the%20ThreadPool%20defaults%20regarding%20the%20number%20of%20maximum%20or%20minimum%20worker%20and%2For%20IO%20threads%20to%20troubleshoot%20a%20problem%20or%20test%20application%20behavior%20with%20different%20settings.%20There%20is%20conflicting%20information%20out%20there%20on%20how%20to%20change%20the%20ThreadPool%20settings%20for%20an%20ASP.NET%204.x%20web%20app%2C%20so%20the%20purpose%20of%20this%20post%20is%20to%20cover%20how%20to%20make%20those%20changes%20correctly.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CFONT%20color%3D%22%23ff0000%22%3E%3CSTRONG%3E%3CSPAN%20style%3D%22text-align%3A%20left%3B%20color%3A%20%23333333%3B%20text-transform%3A%20none%3B%20line-height%3A%201.7142%3B%20text-indent%3A%200px%3B%20letter-spacing%3A%20normal%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20text-decoration%3A%20none%3B%20word-spacing%3A%200px%3B%20display%3A%20inline%20!important%3B%20white-space%3A%20normal%3B%20cursor%3A%20text%3B%20orphans%3A%202%3B%20float%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20background-color%3A%20%23ffffff%3B%22%3ENOTE%3A%3C%2FSPAN%3E%3C%2FSTRONG%3E%3C%2FFONT%3E%3CSPAN%20style%3D%22text-align%3A%20left%3B%20color%3A%20%23333333%3B%20text-transform%3A%20none%3B%20line-height%3A%201.7142%3B%20text-indent%3A%200px%3B%20letter-spacing%3A%20normal%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20text-decoration%3A%20none%3B%20word-spacing%3A%200px%3B%20display%3A%20inline%20!important%3B%20white-space%3A%20normal%3B%20cursor%3A%20text%3B%20orphans%3A%202%3B%20float%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20background-color%3A%20%23ffffff%3B%22%3E%20We%20generally%20don't%20recommend%20modifying%20the%20CLR%20TP%20thread%20counts%2C%20as%20the%20defaults%20work%20for%20the%20vast%20majority%20of%20scenarios.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSPAN%20style%3D%22text-align%3A%20left%3B%20color%3A%20%23333333%3B%20text-transform%3A%20none%3B%20line-height%3A%201.7142%3B%20text-indent%3A%200px%3B%20letter-spacing%3A%20normal%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20text-decoration%3A%20none%3B%20word-spacing%3A%200px%3B%20display%3A%20inline%20!important%3B%20white-space%3A%20normal%3B%20cursor%3A%20text%3B%20orphans%3A%202%3B%20float%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20background-color%3A%20%23ffffff%3B%22%3EIf%20you%20want%20to%20change%20the%20ThreadPool%20settings%20in%20an%20ASP.NET%20application%2C%20you%20have%20two%20choices%3A%3C%2FSPAN%3E%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3EModify%20the%20%3CA%20title%3D%22system.web%5CprocessModel%22%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fdotnet%2Fapi%2Fsystem.web.configuration.processmodelsection%3Fview%3Dnetframework-4.7.2%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Esystem.web%5CprocessModel%3C%2FA%3E%20element%20in%20the%20machine.config.%20There%20could%20be%20several%20copies%20of%20this%20file%20on%20a%20typical%20server.%20For%20the%20most%20part%2C%20these%20are%20the%20ones%20we%20deal%20with%3A%3CUL%3E%0A%3CLI%3EC%3A%5CWindows%5CMicrosoft.NET%5CFramework%5B64%5D%5Cv2.0.50727%5CCONFIG%5Cmachine.config%3C%2FLI%3E%0A%3CLI%3EC%3A%5CWindows%5CMicrosoft.NET%5CFramework%5B64%5D%5Cv4.0.30319%5CCONFIG%5Cmachine.config%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3C%2FLI%3E%0A%3CLI%3EUse%20%3CA%20title%3D%22ThreadPool.SetMaxThreads%22%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fdotnet%2Fapi%2Fsystem.threading.threadpool.setmaxthreads%3Fview%3Dnetframework-4.7.2%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EThreadPool.SetMaxThreads%3C%2FA%3E%20and%20%3CA%20title%3D%22ThreadPool.SetMinThreads%22%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fdotnet%2Fapi%2Fsystem.threading.threadpool.setminthreads%3Fview%3Dnetframework-4.7.2%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3EThreadPool.SetMinThreads%3C%2FA%3E%20from%20within%20the%20application%20itself%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3EFor%20%231%2C%20here's%20how%20the%20processModel%20section%20is%20declared%20in%20the%20machine.config%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%3CEM%3E%3CFONT%20style%3D%22background-color%3A%20%23ffffff%3B%22%3E%3CSECTION%20name%3D%22%26quot%3BprocessModel%26quot%3B%22%20type%3D%22%26quot%3BSystem.Web.Configuration.ProcessModelSection%2C%22%20system.web%3D%22%22%3EallowDefinition%3D%22MachineOnly%22%20allowLocation%3D%22false%22%2F%3C%2FSECTION%3E%3C%2FFONT%3E%3C%2FEM%3E%3CFONT%20style%3D%22background-color%3A%20%23ffffff%3B%22%3E%3CEM%3E%26gt%3B%3C%2FEM%3E%3CBR%20%2F%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CEM%3EallowDefinition%3D%22MachineOnly%22%3C%2FEM%3E%20means%20this%20section%2Felement%20can%26nbsp%3B%3CSTRONG%3Eonly%3C%2FSTRONG%3E%20be%20configured%20in%20the%20machine.config%2C%20and%20not%20any%20other%20downlevel%20config.%20The%26nbsp%3B%3CEM%3EallowLocation%3D%22false%22%26nbsp%3B%3C%2FEM%3Emeans%20this%20section%20cannot%20be%20placed%20in%20a%20%3CLOCATION%3E%20tag.%3C%2FLOCATION%3E%3C%2FP%3E%0A%3CP%3EThis%20means%20if%20you%20try%20to%20change%20the%20processModel%20element%20in%20an%20app's%20web.config%20or%20try%20to%20modify%20a%20copy%20of%20one%20inside%20a%20location%20tag%2C%20you'll%20receive%20an%20error.%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EA%20modifed%20processModel%20element%20could%20look%20like%20this%3A%3CBR%20%2F%3E%3CEM%3E%3CPROCESSMODEL%20autoconfig%3D%22%26quot%3Bfalse%26quot%3B%22%20maxworkerthreads%3D%22%26quot%3B100%26quot%3B%22%20minworkerthreads%3D%22%26quot%3B2%26quot%3B%22%20maxiothreads%3D%22%26quot%3B100%26quot%3B%22%20miniothreads%3D%22%26quot%3B2%26quot%3B%22%3E%3C%2FPROCESSMODEL%3E%3C%2FEM%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EFor%20any%20explicit%20thread%20counts%20to%20be%20honored%2C%20you'd%20need%20to%20set%20autoConfig%3D%22false%22%20-%20by%20default%20it's%20set%20to%20true.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ESome%20folks%20have%20tried%20placing%20a%20modified%20processModel%20element%20into%20a%20separate%20.config%20file%2C%20then%20configuring%20the%20IIS%20host's%20application%20pool's%20CLRConfigFile%20property%20to%20load%20that%20file.%20(This%20feature%20is%20described%20%3CA%20title%3D%22Setting%20an%20ASP.NET%20Config%20File%20per%20Application%20Pool%22%20href%3D%22https%3A%2F%2Fweblogs.asp.net%2Fowscott%2Fsetting-an-aspnet-config-file-per-application-pool%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehere%3C%2FA%3E.)%20%3CSTRONG%3EThis%20does%20not%20work%20for%20modifying%20the%20.NET%20ThreadPool%3C%2FSTRONG%3E%2C%20and%20will%20not%20modify%20the%20actual%20%3CPROCESSMODEL%3E%20settings%20that%20get%20pulled-in.%3C%2FPROCESSMODEL%3E%3C%2FP%3E%0A%3CP%3EThis%20also%20means%20modifying%20the%20Aspnet.config%20file%20that%20exists%20in%20the%20Framework%5B64%5D%5C%5Bversion%5D%5C%20directory%20to%20add%20a%20system.web%5CprocessModel%20element%20will%20not%20work.%20We%20are%20limited%20to%20changing%20this%20element%20in%20the%20machine.config%20only.%3C%2FP%3E%0A%3CP%3EBut%20wait%2C%20doesn't%20editing%20the%20machine.config%20affect%20the%20entire%20server%3F%26nbsp%3BYes%2C%20it%20does!%20Granted%2C%20we're%20only%20editing%20the%20system.web%20section%2C%20so%20only%20apps%20that%20consume%20that%20section%20will%20be%20modified.%20Still%2C%20this%20is%20a%20reason%20to%20not%20make%20the%20change%20here%2C%20even%20though%20you%20can.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThat%20pretty%20much%20leaves%20it%20up%20to%20the%20application%20itself%2C%20via%20option%20%232%20above.%20You%20can%20make%20the%20change%20anywhere%20in%20the%20app%20(even%20on%20an%20aspx%20page%20or%20an%20MVC%20View%2C%20for%20example)%20and%20it%20will%20stick%20for%20the%20rest%20of%20the%20app's%20lifetime%2C%20or%20until%20it%20gets%20changed%20again.%20When%20the%20application%20pool%2Fdomain%2Fetc.%20is%20recycled%2C%20it%20will%20pull%20the%20defaults%20until%20your%20call%20to%20modify%20the%20TP%20is%20made%20again.%20(I'll%20make%20another%20post%20to%20demonstrate%20these%20defaults.)%3C%2FP%3E%0A%3CP%3EOne%20idea%20is%20to%20use%20the%20app's%20*.config%20(or%20wherever%20you're%20storing%20app%20settings)%20to%20store%20your%20desired%20changes%2C%20then%20pull%20those%20values%20into%20the%20app%20and%20apply%20them%20early-on%20in%20the%20application's%20lifetime.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EAgain%2C%20we%20don't%20recommend%20modifying%20the%20ThreadPool%20counts%20unless%20absolutely%20necessary.%20This%20post%20was%20just%20to%20show%20how%20to%20make%20the%20changes%20so%20they%20stick.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-357985%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%20style%3D%22display%3A%20inline%20!important%3B%20float%3A%20none%3B%20background-color%3A%20%23ffffff%3B%20color%3A%20%23333333%3B%20cursor%3A%20text%3B%20font-family%3A%20inherit%3B%20font-size%3A%2016px%3B%20font-style%3A%20normal%3B%20font-variant%3A%20normal%3B%20font-weight%3A%20300%3B%20letter-spacing%3A%20normal%3B%20line-height%3A%201.7142%3B%20orphans%3A%202%3B%20text-align%3A%20left%3B%20text-decoration%3A%20none%3B%20text-indent%3A%200px%3B%20text-transform%3A%20none%3B%20-webkit-text-stroke-width%3A%200px%3B%20white-space%3A%20normal%3B%20word-spacing%3A%200px%3B%22%3EThere%20is%20conflicting%20information%20out%20there%20on%20how%20to%20change%20the%20ThreadPool%20settings%20for%20an%20ASP.NET%204.x%20web%20app%2C%20so%20the%20purpose%20of%20this%20post%20is%20to%20cover%20how%20to%20make%20those%20changes%20correctly.%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-TEASER%3E
Microsoft

One common problem we see is the blocking of .NET ThreadPool threads. This blocking can lead to ThreadPool thread starvation, and sometimes even deadlocks.

This is especially true as of late with more and more folks using asynchronous code, and trying to convert existing, synchronous methods into async, but leaving parts of the code sync.

I don't go into the above scenarios in this post; but, some folks want to change the ThreadPool defaults regarding the number of maximum or minimum worker and/or IO threads to troubleshoot a problem or test application behavior with different settings. There is conflicting information out there on how to change the ThreadPool settings for an ASP.NET 4.x web app, so the purpose of this post is to cover how to make those changes correctly.

 

NOTE: We generally don't recommend modifying the CLR TP thread counts, as the defaults work for the vast majority of scenarios.

 

If you want to change the ThreadPool settings in an ASP.NET application, you have two choices:

  1. Modify the system.web\processModel element in the machine.config. There could be several copies of this file on a typical server. For the most part, these are the ones we deal with:
    • C:\Windows\Microsoft.NET\Framework[64]\v2.0.50727\CONFIG\machine.config
    • C:\Windows\Microsoft.NET\Framework[64]\v4.0.30319\CONFIG\machine.config
  2. Use ThreadPool.SetMaxThreads and ThreadPool.SetMinThreads from within the application itself

For #1, here's how the processModel section is declared in the machine.config:

            <section name="processModel" type="System.Web.Configuration.ProcessModelSection, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" allowDefinition="MachineOnly" allowLocation="false"/>

 

allowDefinition="MachineOnly" means this section/element can only be configured in the machine.config, and not any other downlevel config. The allowLocation="false" means this section cannot be placed in a <location> tag.

This means if you try to change the processModel element in an app's web.config or try to modify a copy of one inside a location tag, you'll receive an error. 

 

A modifed processModel element could look like this:
<processModel autoConfig="false" maxWorkerThreads="100" minWorkerThreads="2" maxIoThreads="100" minIoThreads="2" />

 

For any explicit thread counts to be honored, you'd need to set autoConfig="false" - by default it's set to true.

 

Some folks have tried placing a modified processModel element into a separate .config file, then configuring the IIS host's application pool's CLRConfigFile property to load that file. (This feature is described here.) This does not work for modifying the .NET ThreadPool, and will not modify the actual <processModel> settings that get pulled-in.

This also means modifying the Aspnet.config file that exists in the Framework[64]\[version]\ directory to add a system.web\processModel element will not work. We are limited to changing this element in the machine.config only.

But wait, doesn't editing the machine.config affect the entire server? Yes, it does! Granted, we're only editing the system.web section, so only apps that consume that section will be modified. Still, this is a reason to not make the change here, even though you can.

 

That pretty much leaves it up to the application itself, via option #2 above. You can make the change anywhere in the app (even on an aspx page or an MVC View, for example) and it will stick for the rest of the app's lifetime, or until it gets changed again. When the application pool/domain/etc. is recycled, it will pull the defaults until your call to modify the TP is made again. (I'll make another post to demonstrate these defaults.)

One idea is to use the app's *.config (or wherever you're storing app settings) to store your desired changes, then pull those values into the app and apply them early-on in the application's lifetime.

 

Again, we don't recommend modifying the ThreadPool counts unless absolutely necessary. This post was just to show how to make the changes so they stick.