Thread vs ThreadPool

137

Qual é a diferença entre usar um novo thread e usar um thread do pool de threads? Quais são os benefícios de desempenho e por que devo considerar o uso de um thread do pool em vez de um que eu criei explicitamente? Estou pensando especificamente em .NET aqui, mas exemplos gerais são bons.

Mark Ingram
fonte

Respostas:

110

O pool de threads fornecerá benefícios para operações frequentes e relativamente curtas

  • Reutilizando threads que já foram criados em vez de criar novos (um processo caro)
  • Limitar a taxa de criação de threads quando houver uma explosão de solicitações de novos itens de trabalho (acredito que isso seja apenas no .NET 3.5)

    • Se você enfileirar 100 tarefas do conjunto de encadeamentos, ele usará apenas quantos encadeamentos já foram criados para atender a essas solicitações (por exemplo, 10). O pool de threads fará verificações frequentes (acredito que a cada 500ms no 3.5 SP1) e, se houver tarefas na fila, ele criará um novo thread. Se suas tarefas forem rápidas, o número de novos threads será pequeno e a reutilização dos 10 threads para tarefas curtas será mais rápida do que criar 100 threads antecipadamente.

    • Se sua carga de trabalho consistentemente receber um grande número de solicitações de conjunto de encadeamentos, o conjunto de encadeamentos se ajustará à sua carga de trabalho criando mais encadeamentos no conjunto pelo processo acima, para que haja um número maior de encadeamentos disponíveis para processar solicitações

    • verifique aqui para obter informações mais detalhadas sobre como o pool de threads funciona sob o capô

Criar você mesmo um novo encadeamento seria mais apropriado se o trabalho fosse relativamente longo (provavelmente em torno de um ou dois segundos, mas depende da situação específica)

@Krzysztof - Os threads do pool de threads são threads de segundo plano que serão interrompidos quando o thread principal terminar. Os threads criados manualmente são o primeiro plano por padrão (continuará sendo executado após o término do thread principal), mas pode ser definido como segundo plano antes de chamar Start neles.

Karg
fonte
5
A única coisa que me interessa é a seguinte declaração do MSDN ( msdn.microsoft.com/en-us/library/1c9txz50.aspx ) "Um thread em segundo plano é executado apenas quando o número de threads em primeiro plano em execução é menor que o número de processadores . " Então, isso significa que, ao dividir o trabalho entre os núcleos, os segmentos em primeiro plano têm prioridade?
Cdiggins # 03/02
1
➤ Você não pode abortar ou interromper um encadeamento do pool de encadeamentos. Can't Você não pode ingressar em um thread do pool de threads. Para conseguir isso, você deve usar outros mecanismos
Zinov 29/03/2015
14

O pool de threads gerenciado pelo .NET: -

  • Dimensiona-se com base na carga de trabalho atual e no hardware disponível
  • Contém threads de trabalho e threads de porta de conclusão (que são usados ​​especificamente para atender às E / S)
  • É otimizado para um grande número de operações de vida relativamente curta

Existem outras implementações de conjunto de encadeamentos que podem ser mais apropriadas para operações de longa execução.

Especificamente, use um pool de threads para impedir que seu aplicativo crie muitos threads. O recurso mais importante de um pool de threads é a fila de trabalho. Ou seja, quando sua máquina estiver suficientemente ocupada, o pool de threads enfileirará solicitações em vez de gerar mais threads imediatamente.

Portanto, se você criar um número pequeno e limitado de threads, crie você mesmo. Se você não pode determinar antecipadamente quantos threads podem ser criados (por exemplo, eles são criados em resposta às E / S recebidas) e seu trabalho terá vida curta, use o pool de threads. Se você não souber quantos, mas o trabalho deles será de longa duração, não há nada na plataforma para ajudá-lo - mas você poderá encontrar implementações alternativas de pool de encadeamentos que se encaixam.

Martin
fonte
No .NET, você pode usar portas de conclusão sem o pool de threads? Eu estava sob o pressuposto de que os métodos assíncrono E / S eram a única maneira (em .NET) e que eles usam o pool de threads
Karg
10

Além disso

new Thread().Start()

gera um thread em primeiro plano que não morre se você fechar o programa. ThreadPool threads são threads de segundo plano que morrem quando você fecha o aplicativo.


fonte
11
Você sempre pode definir um segmento como plano de fundo. Eles são apenas o primeiro plano por padrão.
Kris Erickson
3
nemo: var t = novo Thread (...); t.BackgroundThread = true; t.Start ();
Ricardo Amores
18
Esclarecimentos sobre o termo "programa". Um aplicativo de desktop é executado em um processo e possui pelo menos um thread em primeiro plano que gerencia a interface do usuário. Esse processo continuará sendo executado enquanto houver threads em primeiro plano. Quando você fecha um aplicativo da área de trabalho, o thread da interface do usuário em primeiro plano é interrompido, mas você não necessariamente parou o processo se ele tiver outros segmentos em primeiro plano.
G-Wiz
8

Fiquei curioso sobre o uso relativo de recursos para isso e fiz uma referência no meu laptop Intel i5 de dois núcleos 2012 usando a versão .net 4.0 do Windows 8. Os Pools de threads levaram em média 0,035ms para começar onde os Threads tiveram uma média de 5,06 em. Em outras palavras, o Thread no pool iniciou cerca de 300x mais rápido para um grande número de threads de vida curta. Pelo menos no segmento testado (100-2000), o tempo total por segmento parecia bastante constante.

Este é o código que foi comparado:

    for (int i = 0; i < ThreadCount; i++) {
        Task.Run(() => { });
    }

    for (int i = 0; i < ThreadCount; i++) {
        var t = new Thread(() => { });
        t.Start();
    }

insira a descrição da imagem aqui

PeterM
fonte
5
Eu acho que é porque o ThreadPool reutilizar os tópicos criados em vez de criar novos (o que é muito caro)
fabriciorissetto
3

Verifique aqui para um tópico anterior:

Quando não devo usar o ThreadPool no .Net?

O resumo é que o Threadpool é bom se você precisar gerar muitos threads de curta duração, enquanto o uso de Threads oferece um pouco mais de controle.

biozinco
fonte
1

O armazenamento local de encadeamentos não é uma boa ideia com conjuntos de encadeamentos. Dá aos tópicos uma "identidade"; nem todos os threads são iguais mais. Agora, os conjuntos de encadeamentos são especialmente úteis se você precisar de um monte de encadeamentos idênticos, prontos para realizar seu trabalho sem sobrecarga de criação.

MSalters
fonte
1

Se você precisar de muitos threads, provavelmente desejará usar um ThreadPool. Eles reutilizam threads, poupando a sobrecarga da criação de threads.

Se você só precisa de um thread para fazer algo, o Thread provavelmente é o mais fácil.

Rob Prouse
fonte
1

A principal necessidade de threads de theadpool é lidar com pequenas tarefas curtas que devem ser concluídas quase que instantaneamente. Os manipuladores de interrupção de hardware geralmente são executados em um contexto de empilhamento que não seria adequado para código que não é do kernel, mas um manipulador de interrupção de hardware pode descobrir que um retorno de chamada de conclusão de E / S no modo de usuário deve ser executado o mais rápido possível. Criar um novo encadeamento com o objetivo de executar uma coisa dessas seria um exagero enorme. Ter alguns encadeamentos pré-criados que podem ser despachados para executar retornos de chamada de conclusão de E / S ou outras coisas semelhantes é muito mais eficiente.

Um aspecto fundamental desses encadeamentos é que, se os métodos de conclusão de E / S sempre são concluídos essencialmente instantaneamente e nunca bloqueiam, e o número de encadeamentos que atualmente estão executando esses métodos é pelo menos igual ao número de processadores, a única maneira de qualquer outro encadeamento pode ser executado antes que um dos métodos mencionados termine, se um dos outros métodos bloquear ou se o tempo de execução exceder um intervalo de tempo de segmentação normal; nenhum deles deve ocorrer com muita frequência se o conjunto de encadeamentos for usado como pretendido.

Se não se espera que um método saia dentro de 100ms aproximadamente quando inicia a execução, o método deve ser executado por outros meios que não o pool principal de threads. Se houver muitas tarefas a serem executadas que consomem muita CPU, mas não bloqueiam, pode ser útil despachá-las usando um conjunto de encadeamentos de aplicativos (um por núcleo de CPU) que é separado do conjunto de encadeamentos "principal", pois o uso mais threads do que núcleos serão contraproducentes ao executar tarefas que não consomem muita energia da CPU. Se, no entanto, um método demorar um segundo ou mais para ser executado e passar a maior parte do tempo bloqueado, o método provavelmente deverá ser executado em um encadeamento dedicado e quase certamente não deverá ser executado em um encadeamento de conjunto de encadeamentos principais. Se uma operação de longa duração precisar ser acionada por algo como um retorno de chamada de E / S,

supercat
fonte
0

Em geral (nunca usei o .NET), um pool de threads seria usado para fins de gerenciamento de recursos. Ele permite que restrições sejam configuradas no seu software. Isso também pode ser feito por motivos de desempenho, pois a criação de novos threads pode ser cara.

Também pode haver razões específicas do sistema. Em Java (novamente, não sei se isso se aplica ao .NET), o gerente dos encadeamentos pode aplicar variáveis ​​específicas do encadeamento à medida que cada encadeamento é retirado do pool e desmarcá-las quando são retornadas (maneira comum de passar algo como uma identidade).

Restrição de exemplo: eu tenho apenas 10 conexões de banco de dados, portanto, permitiria apenas 10 threads de trabalho para acessar o banco de dados.

Isso não significa que você não deve criar seus próprios encadeamentos, mas há condições sob as quais faz sentido usar um pool.

Robin
fonte
0

Usar um pool é uma boa ideia, se você não souber ou não puder controlar quantos threads serão criados.

Basta ter um problema com um formulário usando thread para atualizar algum campo de um banco de dados em um evento de posição alterada de um controle de lista (evite o freez). Demorou 5 minutos para o meu usuário ter um erro no banco de dados (muita conexão com o Access) porque ele estava mudando a posição da lista muito rápido ...

Sei que há outra maneira de resolver o problema básico (incluindo a não utilização do acesso), mas o pool é um bom começo.

Marco Guignard
fonte
0

Tópico :

  1. Criar um thread é muito mais lento do que usar o pool de threads.
  2. Você pode alterar a prioridade de um encadeamento.
  3. O número máximo de encadeamentos em um processo relacionado aos recursos.
  4. O encadeamento está no nível do SO e é controlado pelo SO.
  5. Usar o Thread é uma opção melhor quando a tarefa é relativamente longa

Pool de segmentos :

  1. A execução de um Thread no pool de threads é muito mais rápida do que a criação direta de um Thread.
  2. Você não pode alterar a prioridade de uma execução de thread com base no pool de threads.
  3. Há apenas um pool de threads por processo.
  4. O pool de threads é gerenciado pelo CLR.
  5. O pool de threads é útil para operações de curta duração.
  6. O número de threads no pool de threads está relacionado à carga do aplicativo.
  7. Tarefas TPL executadas com base no pool de threads
Seyedraouf Modarresi
fonte