Opções de configuração de execução para threading

Este artigo detalha as configurações que você pode usar para configurar o threading no .NET.

Observação

O .NET 6 usa o prefixo DOTNET_ como padrão em vez de COMPlus_ para variáveis de ambiente que configuram o comportamento de tempo de execução do .NET. No entanto, o prefixo COMPlus_ continuará funcionando. Se você estiver usando uma versão anterior do runtime do .NET, continue usando o prefixo COMPlus_ para variáveis de ambiente.

Usar todos os grupos de CPU no Windows

  • Em computadores que têm vários grupos de CPU, essa configuração define se os componentes como o pool de threads usam todos os grupos de CPU ou apenas o grupo de CPU primário do processo. A configuração também afeta o que Environment.ProcessorCount retorna.
  • Quando essa configuração está habilitada, todos os grupos de CPU são usados e os threads também são distribuídos automaticamente entre grupos de CPU por padrão.
  • Essa configuração é habilitada por padrão no Windows 11 e versões posteriores e desabilitada por padrão no Windows 10 e versões anteriores. Para que essa configuração entre em vigor quando habilitada, o GC também deve ser configurado para usar todos os grupos de CPU. Para obter mais informações, consulte Grupos de CPU do GC.
Nome da configuração Valores
runtimeconfig.json N/D N/D
Variável de ambiente COMPlus_Thread_UseAllCpuGroups ou DOTNET_Thread_UseAllCpuGroups 0 -desabilitado
1 – Habilitado

Atribuir threads a grupos de CPU no Windows

  • Em computadores que têm vários grupos de CPU e todos os grupos de CPU estão sendo usados, essa configuração define se os threads são distribuídos automaticamente entre grupos de CPU.
  • Quando essa configuração está habilitada, novos threads são atribuídos a um grupo de CPU de uma maneira que tenta preencher totalmente um grupo de CPU que já está em uso antes de utilizar um novo grupo de CPU.
  • Essa configuração é habilitada por padrão.
Nome da configuração Valores
runtimeconfig.json N/D N/D
Variável de ambiente COMPlus_Thread_AssignCpuGroups ou DOTNET_Thread_AssignCpuGroups 0 -desabilitado
1 – Habilitado

Mínimo de thread

  • Especifica o número mínimo de threads para o pool de threads de trabalho.
  • Corresponde ao método ThreadPool.SetMinThreads.
Nome da configuração Valores
runtimeconfig.json System.Threading.ThreadPool.MinThreads Um inteiro que representa o número mínimo de threads
Propriedade do MSBuild ThreadPoolMinThreads Um inteiro que representa o número mínimo de threads
Variável de ambiente N/D N/D

Exemplos

Arquivo runtimeconfig.json:

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

Arquivo runtimeconfig.template.json:

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

Arquivo de projeto:

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

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

</Project>

Máximo de threads

  • Especifica o número máximo de threads para o pool de threads de trabalho.
  • Corresponde ao método ThreadPool.SetMaxThreads.
Nome da configuração Valores
runtimeconfig.json System.Threading.ThreadPool.MaxThreads Um inteiro que representa o número máximo de threads
Propriedade do MSBuild ThreadPoolMaxThreads Um inteiro que representa o número máximo de threads
Variável de ambiente N/D N/D

Exemplos

Arquivo runtimeconfig.json:

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

Arquivo runtimeconfig.template.json:

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

Arquivo de projeto:

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

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

</Project>

Pool de threads do Windows

  • Para projetos no Windows, configura se o gerenciamento de threads do pool de threads é delegado ao pool de threads do Windows.
  • Se você omitir essa configuração ou a plataforma não for Windows, o pool de threads do .NET será usado.
  • Somente os aplicativos publicados com AOT Nativo no Windows usam o pool de threads do Windows por padrão, para o qual você pode optar por usar o pool de threads do .NET desabilitando a configuração.
  • O pool de threads do Windows pode ter um desempenho melhor em alguns casos, como nos casos em que o número mínimo de threads está configurado com um valor alto ou quando o pool de threads do Windows já está sendo muito usado pelo aplicativo. Também pode haver casos em que o pool de threads do .NET tenha um desempenho melhor, como no tratamento de E/S pesada em computadores maiores. É aconselhável verificar as métricas de desempenho ao alterar essa configuração.
  • Não há suporte para algumas APIs ao usar o pool de threads do Windows, como ThreadPool.SetMinThreads, ThreadPool.SetMaxThreads e ThreadPool.BindHandle(SafeHandle). As configurações do pool de threads para threads mínimos e máximos também não são eficazes. Uma alternativa para ThreadPool.BindHandle(SafeHandle) é a classe ThreadPoolBoundHandle.
Nome da configuração Valores Versão introduzida
runtimeconfig.json System.Threading.ThreadPool.UseWindowsThreadPool true - habilitado
false -desabilitado
.NET 8
Propriedade do MSBuild UseWindowsThreadPool true - habilitado
false -desabilitado
.NET 8
Variável de ambiente DOTNET_ThreadPool_UseWindowsThreadPool 1 – Habilitado
0 -desabilitado
.NET 8

Exemplos

Arquivo runtimeconfig.json:

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

Arquivo runtimeconfig.template.json:

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

Arquivo de projeto:

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

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

</Project>

Injeção de thread em resposta ao bloqueio de itens de trabalho

Em alguns casos, o pool de threads detecta itens de trabalho que bloqueiam seus threads. Para compensar, ele injeta mais threads. No .NET 6+, você pode usar as configurações a seguir de runtime para configurar a injeção de thread em resposta ao bloqueio de itens de trabalho. Atualmente, essas configurações têm efeito apenas para itens de trabalho que aguardam a conclusão de outra tarefa, como em casos típicos de sincronização sobre assíncrono.

Nome da configuração runtimeconfig.json Descrição Versão introduzida
System.Threading.ThreadPool.Blocking.ThreadsToAddWithoutDelay_ProcCountFactor Depois que a contagem de threads com base MinThreads é atingida, esse valor (depois de multiplicado pela contagem de processadores) especifica quantos threads adicionais podem ser criados sem atraso. .NET 6
System.Threading.ThreadPool.Blocking.ThreadsPerDelayStep_ProcCountFactor Depois que a contagem de threads com base em ThreadsToAddWithoutDelay é atingida, esse valor (depois de multiplicado pela contagem de processadores) especifica após quantos threads um DelayStepMs adicional seria adicionado ao atraso antes de cada novo thread ser criado. .NET 6
System.Threading.ThreadPool.Blocking.DelayStepMs Depois que a contagem de threads com base em ThreadsToAddWithoutDelay for atingida, esse valor especifica quanto atraso adicional adicionar por threads ThreadsPerDelayStep, que seria aplicado antes de cada novo thread ser criado. .NET 6
System.Threading.ThreadPool.Blocking.MaxDelayMs Depois que a contagem de threads com base em ThreadsToAddWithoutDelay for atingida, esse valor especifica o atraso máximo a ser usado antes que cada novo thread seja criado. .NET 6
System.Threading.ThreadPool.Blocking.IgnoreMemoryUsage Por padrão, a taxa de injeção de thread em resposta ao bloqueio é limitada pela heurística que determina se há memória física suficiente disponível. Em algumas situações, pode ser preferível injetar threads mais rapidamente, mesmo em situações de memória baixa. Você pode desabilitar a heurística de uso de memória desativando esse botão. .NET 7

Como as configurações entrarão em vigor

  • Depois que a contagem de threads com base em MinThreads for atingida, até threads adicionais ThreadsToAddWithoutDelay poderão ser criados sem atraso.
  • Depois disso, antes de cada thread adicional ser criado, um atraso é induzido, começando com DelayStepMs.
  • Para cada thread ThreadsPerDelayStep adicionado com um atraso, um DelayStepMs adicional é adicionado ao atraso.
  • O atraso não pode exceder MaxDelayMs.
  • Atrasos só são induzidos antes de criar threads. Se os threads já estiverem disponíveis, eles serão liberados sem demora para compensar o bloqueio de itens de trabalho.
  • O uso e os limites de memória física também são usados e, além de um limite, o sistema muda para uma injeção de thread mais lenta.

Exemplos

Arquivo runtimeconfig.json:

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

Arquivo runtimeconfig.template.json:

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

AutoreleasePool para threads gerenciados

Essa opção configura se cada thread gerenciado recebe um NSAutoreleasePool implícito ao ser executado em uma plataforma macOS com suporte.

Nome da configuração Valores Versão introduzida
runtimeconfig.json System.Threading.Thread.EnableAutoreleasePool true ou false .NET 6
Propriedade do MSBuild AutoreleasePoolSupport true ou false .NET 6
Variável de ambiente N/D N/D N/D

Exemplos

Arquivo runtimeconfig.json:

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

Arquivo runtimeconfig.template.json:

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

Arquivo de projeto:

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

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

</Project>