Para presumir uma melhoria de velocidade devido a qualquer forma de multi-computação, você deve presumir que várias tarefas baseadas em CPU estão sendo executadas simultaneamente em vários recursos de computação (geralmente núcleos de processador) ou então que nem todas as tarefas dependem do uso simultâneo de o mesmo recurso - ou seja, algumas tarefas podem depender de um subcomponente do sistema (armazenamento em disco, por exemplo), enquanto algumas tarefas dependem de outro (receber comunicação de um dispositivo periférico) e outras ainda podem exigir o uso de núcleos de processador.
O primeiro cenário é freqüentemente conhecido como programação "paralela". O segundo cenário é frequentemente referido como programação "simultânea" ou "assíncrona", embora "simultâneo" às vezes também seja usado para se referir ao caso de meramente permitir que um sistema operacional intercale a execução de várias tarefas, independentemente de tal execução ter coloque em série ou se vários recursos puderem ser usados para alcançar a execução paralela. Neste último caso, "simultâneo" geralmente se refere à maneira como a execução é escrita no programa, em vez da perspectiva da simultaneidade real da execução da tarefa.
É muito fácil falar sobre tudo isso com suposições tácitas. Por exemplo, alguns são rápidos em fazer uma afirmação como "E / S assíncrona será mais rápida do que E / S multiencadeada". Essa afirmação é duvidosa por vários motivos. Em primeiro lugar, pode ser o caso de que algum determinado framework de E / S assíncrono seja implementado precisamente com multi-threading, caso em que eles são um no mesmo e não faz sentido dizer que um conceito "é mais rápido que" o outro .
Em segundo lugar, mesmo no caso em que há uma implementação de thread único de uma estrutura assíncrona (como um loop de evento de thread único), você ainda deve fazer uma suposição sobre o que esse loop está fazendo. Por exemplo, uma coisa boba que você pode fazer com um loop de evento de thread único é solicitar que ele conclua de forma assíncrona duas tarefas diferentes exclusivamente relacionadas à CPU. Se você fizesse isso em uma máquina com apenas um único núcleo de processador idealizado (ignorando as otimizações de hardware modernas), executar essa tarefa "de forma assíncrona" não teria um desempenho diferente do que executá-la com dois threads gerenciados independentemente ou apenas com um único processo - - a diferença pode se resumir à troca de contexto de thread ou otimizações de agendamento do sistema operacional, mas se ambas as tarefas forem para a CPU, serão semelhantes em ambos os casos.
É útil imaginar muitos dos casos incomuns ou estúpidos que você pode encontrar.
"Assíncrono" não precisa ser simultâneo, por exemplo, como acima: você executa "de forma assíncrona" duas tarefas associadas à CPU em uma máquina com exatamente um núcleo de processador.
A execução multi-threaded não precisa ser simultânea: você gera duas threads em uma máquina com um único núcleo de processador ou pede a duas threads para adquirir qualquer outro tipo de recurso escasso (imagine, digamos, um banco de dados de rede que só pode estabelecer um conexão de cada vez). A execução dos threads pode ser intercalada, no entanto, o planejador do sistema operacional achar necessário, mas seu tempo de execução total não pode ser reduzido (e será aumentado a partir da troca de contexto do thread) em um único núcleo (ou mais geralmente, se você gerar mais threads do que o existente núcleos para executá-los ou ter mais threads pedindo um recurso do que o recurso pode sustentar). A mesma coisa também se aplica ao multiprocessamento.
Portanto, nem E / S assíncrona nem multi-threading oferecem qualquer ganho de desempenho em termos de tempo de execução. Eles podem até mesmo desacelerar as coisas.
Se você definir um caso de uso específico, no entanto, como um programa específico que faz uma chamada de rede para recuperar dados de um recurso conectado à rede, como um banco de dados remoto, e também faz alguns cálculos ligados à CPU local, você pode começar a raciocinar sobre as diferenças de desempenho entre os dois métodos, considerando uma suposição particular sobre o hardware.
As perguntas a serem feitas: Quantas etapas computacionais eu preciso executar e quantos sistemas independentes de recursos existem para executá-las? Existem subconjuntos das etapas computacionais que requerem o uso de subcomponentes de sistema independentes e podem se beneficiar ao fazer isso simultaneamente? Quantos núcleos de processador eu tenho e qual é a sobrecarga de usar vários processadores ou threads para concluir tarefas em núcleos separados?
Se suas tarefas dependem amplamente de subsistemas independentes, uma solução assíncrona pode ser boa. Se o número de threads necessários para lidar com isso fosse grande, de forma que a troca de contexto se tornasse não trivial para o sistema operacional, uma solução assíncrona de thread único seria melhor.
Sempre que as tarefas são vinculadas ao mesmo recurso (por exemplo, várias necessidades para acessar simultaneamente a mesma rede ou recurso local), o multi-threading provavelmente irá introduzir sobrecarga insatisfatória, e enquanto a assincronia de thread único pode introduzir menos sobrecarga, em tal recurso- situação limitada, também não pode produzir uma aceleração. Nesse caso, a única opção (se você quiser uma aceleração) é fazer várias cópias desse recurso disponíveis (por exemplo, vários núcleos de processador se o recurso escasso for CPU; um banco de dados melhor que suporte mais conexões simultâneas se o recurso escasso é um banco de dados com conexão limitada, etc.).
Outra maneira de colocar isso é: permitir que o sistema operacional intercale o uso de um único recurso para duas tarefas não pode ser mais rápido do que simplesmente deixar uma tarefa usar o recurso enquanto a outra espera, então deixar a segunda tarefa terminar em série. Além disso, o custo do programador de intercalação significa que, em qualquer situação real, ele realmente cria uma desaceleração. Não importa se o uso intercalado ocorre da CPU, um recurso de rede, um recurso de memória, um dispositivo periférico ou qualquer outro recurso do sistema.