Fabrício Rissetto
Velocidade
Non-blocking
...
O clock speed dos nossos processadores está estagnando!
The Free Lunch Is Over: A Fundamental Turn Toward Concurrency
in Software - http://www.gotw.ca/publications/concurrency-ddj.htm
Construir um worker para tratamento de eventos
 Obter um número X de eventos através de uma queue
 Enviar esses eventos para uma API paralelamente
var listaEventos = Enumerable.Range(1, 1000);
Parallel.ForEach(listaEventos,
(idEvento) =>
{
ChamadaParaWebService(idEvento);
});
private void ChamadaParaWebService(int idEvento)
{
Console.Write(".");
Thread.Sleep(450);
}
var listaEventos = Enumerable.Range(1, 1000);
listaEventos.ToList().ForEach((idEvento) =>
{
Task.Run(() =>
{
ChamadaParaWebService(idEvento);
});
});
Visa evitar o overhead da criação excessiva de threads
através do uso de um “pool”
Reaproveitamento da threads utilizadas
 Criação e destruição de threads é um processo custoso
 Chamadas SO
 Alocação e desalocação de bloco de memória
 Context Switch
Objetivo final: Tirar o máximo do CPU sem atolar ele
const int quantidadeThreads = 100;
for (int i = 0; i < quantidadeThreads; i++)
{
new Thread(new ThreadStart(() =>
{
while (true)
{
ObtemEventoDaFilaEChamaWebService();
}
})).Start();
}
new Thread(new ThreadStart(() =>
{
//...
})).Start();
Task.Factory.StartNew(() =>
{
//...
}, TaskCreationOptions.LongRunning);
Produz uma nova thread
const int quantidadeThreads = 100;
for (int i = 0; i < quantidadeThreads; i++)
{
new Thread(new ThreadStart(() =>
{
while (true)
{
ObtemEventoDaFilaEChamaWebService();
}
})).Start();
}
const int quantidadeThreads = 100;
for (int i = 0; i < quantidadeThreads; i++)
{
Task.Factory.StartNew(() =>
{
while (true)
{
ObtemEventoDaFilaEChamaWebService();
}
}, TaskCreationOptions.LongRunning);
}
Tasks podem retornar resultados
Com o Wait é possível esperar por várias tasks sem
precisar construir um mecanismo de sinais
Tasks podem ter sua execução encadeada com facilidade
Tasks suportam cancelamento de maneira simples via
token de cancelamento
Exceptions em tasks filhas propagam para tasks pais
Possibilidade de usar as keywords ‘async’ e ‘await’
(com task long running não faz sentido!)
Thread (ou tasks long running)
IO Bound
 Leituras ou escritas em
arquivos
 Chamadas para APIs ou WS
 Escritas em banco de dados
Tasks (thread pool)
CPU Bound
 Cálculos hash
 Operações em matrizes
 Algoritmos recursivos
 Operações de reflection
pseudo-guideline
Já disponíveis!
 Threads somente no .NET Standar 2.0
 Pra versões anteriores usar o “hack” do long running
Não se preocupe em decorar regras ou seguir guidelines,
teste o seu código e descubra o que funciona melhor
E-mail: fabriciorissetto@gmail.com
Blog: fabriciorissetto.com
Obrigado!
Referências:
• http://www.gotw.ca/publications/concurrency-ddj.htm
• http://blog.i3arnon.com/2015/07/02/task-run-long-running/
• http://referencesource.microsoft.com/#mscorlib/system/threadin
g/Tasks/ThreadPoolTaskScheduler.cs,55

Threads tasks e o tal do thread pool

  • 1.
  • 2.
    Velocidade Non-blocking ... O clock speeddos nossos processadores está estagnando! The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software - http://www.gotw.ca/publications/concurrency-ddj.htm
  • 5.
    Construir um workerpara tratamento de eventos  Obter um número X de eventos através de uma queue  Enviar esses eventos para uma API paralelamente
  • 6.
    var listaEventos =Enumerable.Range(1, 1000); Parallel.ForEach(listaEventos, (idEvento) => { ChamadaParaWebService(idEvento); }); private void ChamadaParaWebService(int idEvento) { Console.Write("."); Thread.Sleep(450); }
  • 8.
    var listaEventos =Enumerable.Range(1, 1000); listaEventos.ToList().ForEach((idEvento) => { Task.Run(() => { ChamadaParaWebService(idEvento); }); });
  • 11.
    Visa evitar ooverhead da criação excessiva de threads através do uso de um “pool” Reaproveitamento da threads utilizadas  Criação e destruição de threads é um processo custoso  Chamadas SO  Alocação e desalocação de bloco de memória  Context Switch Objetivo final: Tirar o máximo do CPU sem atolar ele
  • 13.
    const int quantidadeThreads= 100; for (int i = 0; i < quantidadeThreads; i++) { new Thread(new ThreadStart(() => { while (true) { ObtemEventoDaFilaEChamaWebService(); } })).Start(); }
  • 14.
    new Thread(new ThreadStart(()=> { //... })).Start(); Task.Factory.StartNew(() => { //... }, TaskCreationOptions.LongRunning); Produz uma nova thread
  • 16.
    const int quantidadeThreads= 100; for (int i = 0; i < quantidadeThreads; i++) { new Thread(new ThreadStart(() => { while (true) { ObtemEventoDaFilaEChamaWebService(); } })).Start(); }
  • 17.
    const int quantidadeThreads= 100; for (int i = 0; i < quantidadeThreads; i++) { Task.Factory.StartNew(() => { while (true) { ObtemEventoDaFilaEChamaWebService(); } }, TaskCreationOptions.LongRunning); }
  • 18.
    Tasks podem retornarresultados Com o Wait é possível esperar por várias tasks sem precisar construir um mecanismo de sinais Tasks podem ter sua execução encadeada com facilidade Tasks suportam cancelamento de maneira simples via token de cancelamento Exceptions em tasks filhas propagam para tasks pais Possibilidade de usar as keywords ‘async’ e ‘await’ (com task long running não faz sentido!)
  • 19.
    Thread (ou taskslong running) IO Bound  Leituras ou escritas em arquivos  Chamadas para APIs ou WS  Escritas em banco de dados Tasks (thread pool) CPU Bound  Cálculos hash  Operações em matrizes  Algoritmos recursivos  Operações de reflection pseudo-guideline
  • 20.
    Já disponíveis!  Threadssomente no .NET Standar 2.0  Pra versões anteriores usar o “hack” do long running
  • 21.
    Não se preocupeem decorar regras ou seguir guidelines, teste o seu código e descubra o que funciona melhor
  • 22.
    E-mail: fabriciorissetto@gmail.com Blog: fabriciorissetto.com Obrigado! Referências: •http://www.gotw.ca/publications/concurrency-ddj.htm • http://blog.i3arnon.com/2015/07/02/task-run-long-running/ • http://referencesource.microsoft.com/#mscorlib/system/threadin g/Tasks/ThreadPoolTaskScheduler.cs,55

Notas do Editor

  • #3 The CPU requires a fixed number of clock ticks (or clock cycles) to execute each instruction. The faster the clock, the more instructions the CPU can execute per second. Clock speeds are expressed in megahertz (MHz) or gigahertz ((GHz).
  • #4 Quanto mais transistors, mais operações lógicas meu processador consegue fazer por ciclo de clock. Quanto mais operações ele faz por ciclo de clock mais rápido é o clock speed Hj precessadores tem mais cores Isso impacta diretamente a nossa maneira de programar Antigamente a gente poderia assumir que os novos processadores teriam um clock mais rápido e que com isso, executariam nosso código mais rápido sem nenhum esforço da nossa parte pra melhorar performance. Mas isso não é mais verdade e pra escrever código que extrai o máximo desses processadores a gente precisa trabalhar pra isso
  • #6 Disclaimer: tentem aconselho a construírem esse tipo de aplicação Hangfire, NServiceBus, Azure WebJobs  No meu caso o desafio era suportar um negocio que já existia mesmo
  • #7 Então, colocando aquele código ali de cima numa console application, o resultado foi esse:
  • #14 Uma coisa de se tomar cuidado com threads é que as exceções que ocorrem dentro dela afetam o código em que ela ta inserido. Nesse exemplo ai se ocorrer algum erro não tratado dentro daquele método ali (apontar pra ele) todo o bloco while vai parar
  • #15 Atenção 1, se abrir long running a moda louco sem saber a quantiadde vai dar merda! Com tasks não temos essa preocupação, com threads sim! Não considerem tasks long running a mesma coisa que tasks! Atenção 2: Extremamente mal documentado (which is an implementation detail that could be changed) TaskScheduler.Default ???
  • #18 Tomar cuidado que isso é detalhe de implementação, pode mudar a qualquer momento. Está extremamente mau documentado Hj cria uma nova thread, nada garante que sempre vai ser assim
  • #19 async e await There is no CLR support for await. It goes away on compilation. Anything you can write with await you can write without it. Awaiting tasks it is a fancy way of calling ContinueWith :) Decompile an assembly that uses await to see how it works under the covers.
  • #20 Tasks are optimized for a large number of relatively short-lived operations executam em cores separados Threads não é garantido que serão executadas em processadores paralelos pode ser configurado pra executar em um processador específico EM RESUMO: Se tu quer executar um número indeterminado de tarefas que são CPU bound sem correr o risco de atolar o processador, usa task. Se tu quer executar um número indeterminado de tarefas só que elas são long runnning, não tem nada pronto na plataforma pra te ajudar. Aconselho usar tasks long running e testar o resultado, nada de suposições quando se fala em performance.
  • #22 1- Quando se fala em performance não se pode trabalhar com suposições, é preciso testar 2 - Existem outros detalhes de implementação no framework para caso uma tarefa “demore mais do que o comum”. A cada meio segundo de execução contínua de uma task o thread pool ativa uma thread “a mais” para trabalhar (passando assim o número de threads p/ core). Pode ser muita informação, mas saibam que eu conheço muitos programadores .NET, muitos mesmo, e pouquíssimos dominam esse assunto. Se eu pude aqui, nessa rápida apresentação, passar o conteúdo de uma maneira que vocês possam absorver pelo menos uma parte, saibam que vocês já estão um passinho a frente em um assunto que é muito complexo e que pouca gente domina. Espero que tenha sido útil e me desculpem pela chuva de informação. Então É isso aí. Aqui deixo meu contato e estarei disponível ali no coffe pra quem quiser trocar uma ideia. Valeu, vejo vcs ali.