Sync/Async/Multi-thread
You have three ways to code your application, synchronous, asynchronous and multi-threading. But first you need to understand what your application needs to do.
Not just the logic of your application, but the performance, the processes you must have, the response you have to give to the user and the interactions the user has in your application.
After understanding what you have to implement, you have to make a choice. Be aware that you can choose all the options, choose the best option for the process you are coding.
Sync??
Async??
Multi-thread??
To get the explanation, forget programming!
Synchronous
Imagine this, you are a Chef. And you have three tasks to do, you have to cook the potatoes, cook vegetables and clear the dishes.
The synchronous way, you will cook potatoes and you will stand there, until the potatoes are done. Then you cook the vegetables, and again you will wait for the vegetables to be done. After that you will clean the dishes and wait for the dishes to dry. This is like a waterfall plan, to do the next step you need to finish the previous step.
Asynchronous
We will use the same example. You are a Chef.
But now you are asynchronous, so the result will be, start cooking the potatoes, and you put a timer of five minutes (so after five minutes the potatoes are done). But now you will not wait for the potatoes to be done to start cooking the vegetables. You start the vegetables and you put a timer as well.(remember you have the potatoes and vegetables cooking). And now you will start to clear the dishes. But before you start the potatoes timer rings!! You will stop the cleaning, and RUN FOR THE POTATOES(maybe not in caps lock). Now you remove the potatoes and turn off the oven. After this you will start cleaning again.
But wait Chef the vegetables timer also rings, you suspended the cleaning and go to the vegetable to turn off the oven. And now, yes… you start the cleaning and finish it.
Multi-threading
For this, imagine you have three Chefs, each one is doing each task. One for cooking the potatoes, one for the vegetables and other to clean.
But how this works in programming??
Synchronous
A normal code, two methods. FirstCall() and SecondCall(), they print the name method.
Asynchronous
As you can see, we start with the potatoes, then vegetables and finish with the cleaning. But the potatoes take five seconds (5000 ms), the vegetables take six seconds (6000ms) and the cleaning takes two seconds (2000ms).
So the Chef start with the potatoes, then cook vegetables and finish with the cleaning. But the Chef bounce between task. And that behaviour is what is happening with the CPU. We bounce between task to make the process. The CPU doesn’t need to be stuck for finish the potatoes or the vegetables.
class Program{ static async Task Main(string[] args) { Pototoes potatoes = new Pototoes(); potatoes.Cook(5000); Vegetables vegetables = new Vegetables(); vegetables.Cook(6000); Dishes dishes = new Dishes(); dishes.Clean(2000);
Console.Read(); }}internal class Dishes{ internal async Task Clean(int v) { await Task.Delay(v); Console.WriteLine("Dishes are ready"); }}internal class Vegetables{ internal async Task Cook(int v) { await Task.Delay(v); Console.WriteLine("Vegetables are ready"); }}internal class Pototoes{ internal async Task Cook(int v) { await Task.Delay(v); Console.WriteLine("Pototoes are ready"); }}
Problem with Asynchronous
You have a few big problems, with Asynchronous. Like deadlocks.
There are deadlocks because of bad usage with Task.Wait(), using different Context, Task.Result() or simply because crossing of tasks, when task 1 is waiting for task2 and task2 is waiting for task1.
If you want to know more click there.
Multi-threading
Remember now you have three Chefs and each one is responsible for each task.
Each thread is a Chef, each thread is running the process for “cooking potatoes”, “cooking vegetables” and “cleaning”.
As you can see, Console.WriteLine(), don’t have a pattern. And please don’t say that threads and task are the same. (below you have a brief explanation)
Problems with Multi-threading
Increased Complexity − Multi-threaded processes are quite complicated. Coding for these can only be handled by expert programmers.
Complications due to Concurrency − It is difficult to handle concurrency in multi-threaded processes. This may lead to complications and future problems.
Difficult to Identify Errors− Identification and correction of errors is much more difficult in multi-threaded processes as compared to a single threaded processes.
Testing Complications− Testing is a complicated process in multi-threaded programs as compared to a single threaded programs. This is because defects can be timing related and not easy to identify.
Unpredictable results− Multi-threaded programs can sometimes lead to unpredictable results as they are essentially multiple parts of a program that are running at the same time.
Complications for Porting Existing Code − A lot of testing is required for porting existing code in multi-threading. Static variables need to be removed and any code or function calls that are not thread safe need to be replaced.
Task vs thread
Just a simple and fast explanation for those two concepts.
Thread-> is a lower-level concept: if you’re directly starting a thread, you know it will be a separate thread, rather than executing on the thread pool, etc. Thread represents an actual OS-level thread, with its own stack and kernel resources. The problem with Thread is that OS threads are costly. Each thread you have consumed a non-trivial amount of memory for its stack, and adds additional CPU overhead as the processor context-switch between threads.
Task -> is more than just an abstraction of “where to run some code” though-it’s really just “the promise of a result in the future”. Task class from the Task Parallel Library offers the best of both worlds. Like the ThreadPool, a task does not create its own OS thread. Instead, tasks are executed by a TaskScheduler.
Sync/Async/Multi-thread
Tu tens três maneiras de programar seu aplicativo, síncrono, assíncrono e multi-thread. Mas primeiro você precisa entender o que a aplicação precisa fazer.
Não apenas a lógica da aplicação, mas o desempenho, os processos que deve ter, a resposta que deve dar ao user e as interações que o user tem na aplicação.
Depois de entender o que implementar, tens fazer uma escolha. Embora podes escolher as três opções, para se ajustar melhor á tua aplicação.
Sync??
Async??
Multi-thread??
Para entenderes a explicação, esquece a programação.
Síncrono
Imagine isso, tu és um chef de cozinha. E tu tens três tarefas a fazer: cozinhar batatas, cozinhar legumes e limpar a louça.
Da maneira síncrona, tu cozinha batatas e fica ali, até as batatas terminarem. Então depois comecas a cozinhar os legumes e, novamente, esperas que os legumes terminem. Depois disso, limpas a louça e espera que a loiça seque. É como um plano em cascata; para executar o próximo passo, você precisa concluir o passo anterior.
Assíncrono
Vamos usar o mesmo exemplo. Tu és um chef de cozinha.
Mas agora tu és assíncrono, então o resultado será: comece a cozinhar as batatas e colocas um temporizador de cinco minutos (pois as batatas demoram cinco minutos a cozinhar). Mas agora tu não esperaras que as batatas estejam prontas para começar a cozinhar os legumes. Você começa os legumes e coloca um cronômetro também (lembre-te de que tens as batatas e os legumes no fogão). E agora tu começas a limpar a louça. Você interromperá a limpeza e VAIS RETIRAR AS BATATAS (talvez não no caps lock). Depois disso, você começa a limpar novamente.
Mas espere o cronômetro de legumes também toca, você suspendeu a limpeza e foi até aos vegetais para desligar o forno. E agora sim … tu começas a limpeza e termina.
Multi-threading
Para isso, você tem três Chefs, cada um executa uma tarefa. Um para cozinhar as batatas, um para os legumes e outro para limpar.
Como é que isto funciona em codigo??
Synchronous
Um código normal, dois métodos. FirstCall () e SecondCall (), eles imprimem o nome do método. Não á grande magia.
Asynchronous
Como podes ver, começamos com as batatas, depois os legumes e terminamos com a limpeza. Mas as batatas levam cinco segundos (5000 ms), os legumes levam seis segundos (6000ms) e a limpeza leva dois segundos (2000ms).
Então o Chef começa com batatas, depois cozinha legumes e termina com a limpeza. Mas o Chef salta entre as tarefas. E esse comportamento é o que está acontecendo com o CPU. Saltamos entre tarefas para concluir os processos. O CPU não precisa ficar preso para terminar as batatas ou os legumes.
class Program{static async Task Main(string[] args){Pototoes potatoes = new Pototoes();potatoes.Cook(5000);Vegetables vegetables = new Vegetables();vegetables.Cook(6000);Dishes dishes = new Dishes();dishes.Clean(2000);Console.Read();}}internal class Dishes{internal async Task Clean(int v){await Task.Delay(v);Console.WriteLine("Dishes are ready");}}internal class Vegetables{internal async Task Cook(int v){await Task.Delay(v);Console.WriteLine("Vegetables are ready");}}internal class Pototoes{internal async Task Cook(int v){await Task.Delay(v);Console.WriteLine("Pototoes are ready");}}
Problemas com Assíncrono
Você tem alguns grandes problemas com a programação Assíncrona. Como os DeadLocks.
Existem conflitos devido a mau uso do Task.Wait (), usando Context diferente, Task.Result () ou simplesmente porque o cruzamento de task, quando a task1 está aguardando a task2 e a task2 está aguardando a task1.
Se você quiser saber mais, clique aqui.
Multi-threading
Lembre-se agora que você tem três chefs e cada um é responsável por cada tarefa.
Cada thread é um Chef, cada thread está a executar o processo de “cozinhar batatas”, “cozinhar legumes” e “limpar”.
Podes ver que, Console.WriteLine (), não tem um padrão. E, por favor, não digas que threads e task são iguais. (abaixo você tem uma breve explicação)
Problemas com Multi-threading
Maior complexidade — Os processos multi-thread são mais complicados.
Complicações devido à simultaneidade — É difícil lidar com a simultaneidade em processos multi-thread. Isso pode levar a complicações e problemas futuros.
Difícil de identificar erros — A identificação e a correção de erros são muito mais difíceis em processos com vários threads em comparação com processos com thread única.
Testar e Correção— Testar é um processo complicado em programas multithread em comparação com programas single threaded. Isso ocorre porque os defeitos podem estar relacionados ao tempo e não são fáceis de identificar.
Resultados imprevisíveis — Os programas multi-thread às vezes podem levar a resultados imprevisíveis, pois são essencialmente várias partes de um programa em execução ao mesmo tempo.
Task vs thread
Apenas uma explicação simples e rápida para esses dois conceitos.
Thread-> é um conceito de baixo nivel, se estas a iniciar diretament uma thread sabes que será um thread separada, em vez de executar no pool de thread etc. A thread representa um “processo” no nível do SO, com seus próprios recursos de stack e kernel . O problema com o Thread é que as threads do SO são caras. Cada thread consome uma quantidade não trivial de memória para sua stack e adiciona sobrecarga adicional ao CPU à medida que o processador alterna o contexto entre as threads.
Task ->é mais do que apenas uma abstração de “onde executar algum código” — é realmente apenas “a promessa de um resultado no futuro”. A classe Task da Task Parallel Library oferece o melhor dos dois mundos. Como a ThreadPool, uma task não cria a sua própria thread no SO. Em vez disso, as tarefas são executadas por um TaskScheduler.