Opzioni di configurazione del runtime per il threading

Questo articolo illustra nel dettaglio le impostazioni che è possibile usare per configurare il threading in .NET.

Nota

.NET 6 standardizza il prefisso DOTNET_ anziché COMPlus_ per le variabili di ambiente che configurano il comportamento di runtime di .NET. Tuttavia, il prefisso COMPlus_ continuerà a funzionare. Se si usa una versione precedente del runtime .NET, è comunque consigliabile usare il prefisso COMPlus_ per le variabili di ambiente.

Usare tutti i gruppi di CPU in Windows

  • Nei computer con più gruppi di CPU questa impostazione consente di determinare se i componenti, ad esempio il pool di thread, usano tutti i gruppi di CPU o solo il gruppo di CPU primario del processo. L'impostazione influisce anche sul valore restituito da Environment.ProcessorCount.
  • Quando questa impostazione è abilitata, vengono usati tutti i gruppi di CPU e i thread vengono anche distribuiti automaticamente tra i gruppi di CPU per impostazione predefinita.
  • Questa impostazione è abilitata per impostazione predefinita in Windows 11 e versioni successive e disabilitata per impostazione predefinita in Windows 10 e versioni precedenti. Affinché questa impostazione venga applicata quando abilitata, è necessario configurare anche Garbage Collection per l'uso di tutti i gruppi di CPU; Per altre informazioni, vedere Gruppi di CPU per Garbage Collection.
Nome impostazione Valori
runtimeconfig.json N/D N/D
Variabile di ambiente COMPlus_Thread_UseAllCpuGroups oppure DOTNET_Thread_UseAllCpuGroups 0 - disabilitata
1 - abilitata

Assegnare thread a gruppi di CPU in Windows

  • Nei computer con più gruppi di CPU e in cui vengono usati tutti i gruppi di CPU questa impostazione consente di configurare se i thread vengono distribuiti automaticamente tra gruppi di CPU.
  • Quando questa impostazione è abilitata, i nuovi thread vengono assegnati a un gruppo di CPU in modo da provare a popolare completamente un gruppo di CPU già in uso prima di utilizzare un nuovo gruppo di CPU.
  • Questa opzione è attivata per impostazione predefinita.
Nome impostazione Valori
runtimeconfig.json N/D N/D
Variabile di ambiente COMPlus_Thread_AssignCpuGroups oppure DOTNET_Thread_AssignCpuGroups 0 - disabilitata
1 - abilitata

Numero minimo di thread

Nome impostazione Valori
runtimeconfig.json System.Threading.ThreadPool.MinThreads Numero intero che rappresenta il numero minimo di thread
Proprietà MSBuild ThreadPoolMinThreads Numero intero che rappresenta il numero minimo di thread
Variabile di ambiente N/D N/D

Esempi

File runtimeconfig.json:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Threading.ThreadPool.MinThreads": 4
      }
   }
}

File runtimeconfig.template.json:

{
   "configProperties": {
      "System.Threading.ThreadPool.MinThreads": 4
   }
}

File di progetto:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <ThreadPoolMinThreads>4</ThreadPoolMinThreads>
  </PropertyGroup>

</Project>

Numero massimo di thread

  • Specifica il numero massimo di thread per il pool di thread di lavoro.
  • Corrisponde al metodo ThreadPool.SetMaxThreads.
Nome impostazione Valori
runtimeconfig.json System.Threading.ThreadPool.MaxThreads Numero intero che rappresenta il numero massimo di thread
Proprietà MSBuild ThreadPoolMaxThreads Numero intero che rappresenta il numero massimo di thread
Variabile di ambiente N/D N/D

Esempi

File runtimeconfig.json:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Threading.ThreadPool.MaxThreads": 20
      }
   }
}

File runtimeconfig.template.json:

{
   "configProperties": {
      "System.Threading.ThreadPool.MaxThreads": 20
   }
}

File di progetto:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <ThreadPoolMaxThreads>20</ThreadPoolMaxThreads>
  </PropertyGroup>

</Project>

Pool di thread di Windows

  • Per i progetti in Windows, determina se la gestione dei thread del pool di thread è delegata al pool di thread di Windows.
  • Se si omette questa impostazione o la piattaforma non è Windows, viene invece usato il pool di thread .NET.
  • Solo le applicazioni pubblicate con AOT nativo in Windows usano il pool di thread di Windows per impostazione predefinita, per cui è possibile scegliere di usare il pool di thread .NET disabilitando invece l'impostazione di configurazione.
  • Il pool di thread di Windows può offrire prestazioni migliori in alcuni casi, ad esempio nei casi in cui il numero minimo di thread è configurato su un valore elevato o quando il pool di thread di Windows è già usato in modo significativo dall'app. Possono anche verificarsi casi in cui il pool di thread .NET offre prestazioni migliori, ad esempio nella gestione di operazioni a uso elevato di I/O su computer di dimensioni maggiori. È consigliabile controllare le metriche delle prestazioni quando si modifica questa impostazione di configurazione.
  • Alcune API non sono supportate quando si usa il pool di thread di Windows, ad esempio ThreadPool.SetMinThreads, ThreadPool.SetMaxThreads e ThreadPool.BindHandle(SafeHandle). Anche le impostazioni di configurazione del pool di thread per il numero minimo e massimo di thread non sono valide. Un'alternativa a ThreadPool.BindHandle(SafeHandle) è la classe ThreadPoolBoundHandle.
Nome impostazione Valori Versione introdotta
runtimeconfig.json System.Threading.ThreadPool.UseWindowsThreadPool true - abilitata
false - disabilitata
.NET 8
Proprietà MSBuild UseWindowsThreadPool true: abilitata
false - disabilitata
.NET 8
Variabile di ambiente DOTNET_ThreadPool_UseWindowsThreadPool 1 - abilitata
0 - disabilitata
.NET 8

Esempi

File runtimeconfig.json:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Threading.ThreadPool.UseWindowsThreadPool": true
      }
   }
}

File runtimeconfig.template.json:

{
   "configProperties": {
      "System.Threading.ThreadPool.UseWindowsThreadPool": true
   }
}

File di progetto:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <UseWindowsThreadPool>true</UseWindowsThreadPool>
  </PropertyGroup>

</Project>

Inserimento di thread in risposta a elementi di lavoro bloccanti

In alcuni casi il pool di thread rileva elementi di lavoro che bloccano i thread. Per compensare, inserisce più thread. In .NET 6+ è possibile usare le impostazioni di configurazione del runtime seguenti per configurare l'inserimento di thread in risposta a elementi di lavoro bloccanti. Queste impostazioni vengono attualmente applicate solo per gli elementi di lavoro che attendono il completamento di un'altra attività, ad esempio nei casi sincrono su asincrono.

Nome dell'impostazione di runtimeconfig.json Descrizione Versione introdotta
System.Threading.ThreadPool.Blocking.ThreadsToAddWithoutDelay_ProcCountFactor Dopo il raggiungimento del numero di thread basato su MinThreads, questo valore (dopo che viene moltiplicato per il numero di processori) specifica il numero di thread aggiuntivi che possono essere creati senza ritardi. .NET 6
System.Threading.ThreadPool.Blocking.ThreadsPerDelayStep_ProcCountFactor Dopo il raggiungimento del numero di thread basato su ThreadsToAddWithoutDelay, questo valore (dopo che viene moltiplicato per il numero di processori) specifica il numero di thread dopo cui altri DelayStepMs verrebbero aggiunti al ritardo prima della creazione di ogni nuovo thread. .NET 6
System.Threading.ThreadPool.Blocking.DelayStepMs Dopo il raggiungimento del numero di thread basato su ThreadsToAddWithoutDelay, questo valore specifica il ritardo aggiuntivo da aggiungere per ogni thread ThreadsPerDelayStep, che verrebbe applicato prima della creazione di ogni nuovo thread. .NET 6
System.Threading.ThreadPool.Blocking.MaxDelayMs Dopo il raggiungimento del numero di thread basato su ThreadsToAddWithoutDelay, questo valore specifica il ritardo massimo da usare prima della creazione di ogni nuovo thread. .NET 6
System.Threading.ThreadPool.Blocking.IgnoreMemoryUsage Per impostazione predefinita, la frequenza di inserimento di thread in risposta al blocco è limitata dall'euristica che determina se è disponibile memoria fisica sufficiente. In alcune situazioni può essere preferibile inserire thread più rapidamente anche in situazioni di memoria insufficiente. È possibile disabilitare l'euristica dell'utilizzo della memoria disattivando questa opzione. .NET 7

Modalità di applicazione delle impostazioni di configurazione

  • Dopo il raggiungimento del numero di thread basato su MinThreads, è possibile creare fino a ThreadsToAddWithoutDelay thread aggiuntivi senza alcun ritardo.
  • Successivamente, prima di creare ogni thread aggiuntivo, viene indotto un ritardo, a partire da DelayStepMs.
  • Per ogni thread ThreadsPerDelayStep aggiunto con un ritardo, DelayStepMs aggiuntivi vengono aggiunti al ritardo.
  • Il ritardo non può superare il valore di MaxDelayMs.
  • I ritardi vengono indotti solo prima di creare thread. Se i thread sono già disponibili, verranno rilasciati senza ritardo per compensare per gli elementi di lavoro bloccanti.
  • Vengono usati anche i limiti e l'utilizzo della memoria fisica e, oltre una soglia, il sistema passa a un inserimento più lento di thread.

Esempi

File runtimeconfig.json:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Threading.ThreadPool.Blocking.ThreadsToAddWithoutDelay_ProcCountFactor": 5
      }
   }
}

File runtimeconfig.template.json:

{
   "configProperties": {
      "System.Threading.ThreadPool.Blocking.ThreadsToAddWithoutDelay_ProcCountFactor": 5
   }
}

AutoreleasePool per thread gestiti

Questa opzione consente di configurare se ogni thread gestito riceve un implicito NSAutoreleasePool durante l'esecuzione in una piattaforma macOS supportata.

Nome impostazione Valori Versione introdotta
runtimeconfig.json System.Threading.Thread.EnableAutoreleasePool true oppure false .NET 6
Proprietà MSBuild AutoreleasePoolSupport true oppure false .NET 6
Variabile di ambiente N/D N/D N/D

Esempi

File runtimeconfig.json:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Threading.Thread.EnableAutoreleasePool": true
      }
   }
}

File runtimeconfig.template.json:

{
   "configProperties": {
      "System.Threading.Thread.EnableAutoreleasePool": true
   }
}

File di progetto:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <AutoreleasePoolSupport>true</AutoreleasePoolSupport>
  </PropertyGroup>

</Project>