Para obter o melhor desempenho com unidades em execução simultânea, escreva seu próprio conjunto de encadeamentos, onde um conjunto de objetos Thread é criado na inicialização e vá para o bloqueio (anteriormente suspenso), aguardando a execução de um contexto (um objeto com uma interface padrão implementada por seu código).
Tantos artigos sobre Tarefas versus Threads vs. .NET ThreadPool não fornecem realmente o que você precisa para tomar uma decisão de desempenho. Mas quando você os compara, os Threads vencem e, especialmente, um pool de Threads. Eles são distribuídos da melhor maneira entre as CPUs e iniciam mais rapidamente.
O que deve ser discutido é o fato de que a principal unidade de execução do Windows (incluindo o Windows 10) é um encadeamento e a sobrecarga de alternância de contexto do SO geralmente é insignificante. Simplificando, não consegui encontrar evidências convincentes de muitos desses artigos, se o artigo alega desempenho superior ao salvar a alternância de contexto ou um melhor uso da CPU.
Agora, para um pouco de realismo:
A maioria de nós não precisará que nosso aplicativo seja determinístico, e a maioria de nós não tem um histórico de problemas com threads, o que, por exemplo, geralmente ocorre com o desenvolvimento de um sistema operacional. O que escrevi acima não é para iniciantes.
Então, o que pode ser mais importante é discutir o que é fácil de programar.
Se você criar seu próprio pool de encadeamentos, precisará escrever um pouco, pois precisa se preocupar com o rastreamento do status de execução, como simular a suspensão e o resumo e como cancelar a execução - inclusive em um aplicativo em todo o aplicativo desligar. Você também pode ter que se preocupar se deseja aumentar dinamicamente seu pool e também qual limitação de capacidade seu pool terá. Posso escrever esse quadro em uma hora, mas é porque já o fiz tantas vezes.
Talvez a maneira mais fácil de escrever uma unidade de execução seja usar uma tarefa. A vantagem de uma tarefa é que você pode criar uma e iniciá-la em linha no seu código (embora seja necessário cuidado). Você pode passar um token de cancelamento para manipular quando deseja cancelar a tarefa. Além disso, ele usa a abordagem de promessa para encadear eventos e você pode retornar um tipo específico de valor. Além disso, com async e wait, existem mais opções e seu código será mais portátil.
Em essência, é importante entender os prós e os contras com o Tasks vs. Threads vs. o .NET ThreadPool. Se eu precisar de alto desempenho, usarei threads e prefiro usar meu próprio pool.
Uma maneira fácil de comparar é iniciar 512 threads, 512 tarefas e 512 threads ThreadPool. Você encontrará um atraso no início com Threads (portanto, por que gravar um pool de threads), mas todos os 512 Threads estarão em execução em alguns segundos, enquanto os threads Tasks e .NET ThreadPool demoram alguns minutos para iniciar.
Abaixo estão os resultados desse teste (quad core i5 com 16 GB de RAM), dando a cada 30 segundos para execução. O código executado executa E / S de arquivo simples em uma unidade SSD.
Resultado dos testes