Concorrência e Paralelismo (Parte 1) | Entendendo Back-End para Iniciantes (Parte 3)
Introdução
Visão geral da seção: Nesta introdução, Fabio Akita recapitula os conceitos básicos abordados nas partes anteriores do tema de Back-end. Ele menciona tópicos como computadores, sistemas operacionais, processos e threads, compilação e bibliotecas estáticas e dinâmicas, máquinas virtuais e interpretadores.
Recapitulação dos conceitos básicos
- Computadores e sistemas operacionais
- Processos e threads
- Compilação e bibliotecas estáticas e dinâmicas
- Máquinas virtuais e interpretadores
História das linguagens de programação
- Breve visão geral das características de algumas linguagens, como Java, .NET e desenvolvimento mobile.
- Licenças de software
Dificuldades com Concorrência e Paralelismo
Visão geral da seção: Fabio Akita destaca a importância do tema de concorrência e paralelismo no desenvolvimento de software. Ele reconhece que muitos iniciantes têm dificuldade em visualizar esses conceitos. Antes de explorar as linguagens mais óbvias para lidar com concorrência (como Go, Elixir ou Node.js), ele volta à história para ajudar os espectadores a entenderem melhor o assunto.
Desafios na compreensão da concorrência e paralelismo
- Dificuldades enfrentadas pelos iniciantes em visualizar esses conceitos
Mundo Massivamente Paralelo
Visão geral da seção: Fabio Akita destaca a prevalência do processamento paralelo em computadores modernos. Ele menciona a potência dos processadores atuais, desde os modelos mais básicos até os de servidores e GPUs.
Potência dos computadores atuais
- Computadores pessoais, servidores e celulares são massivamente paralelos
- Processadores com múltiplos núcleos e threads
- GPUs com cores CUDA para processamento paralelo
Evolução do Processamento Paralelo
Visão geral da seção: Fabio Akita ressalta como o acesso ao processamento paralelo mudou ao longo do tempo. Ele menciona a evolução dos computadores desde os anos 50 até os dias atuais.
Potência dos computadores no passado
- Comparação entre as capacidades de processamento de computadores antigos e atuais
- Exemplo do IBM 701 nos anos 50
Processamento Paralelo Massivo
Visão geral da seção: Fabio Akita explora exemplos específicos de tecnologias que possibilitam o processamento paralelo massivo, como hyperthreading e placas gráficas.
Exemplos de tecnologias para processamento paralelo massivo
- Tecnologia hyperthreading em CPUs Intel Xeon E7
- Cores CUDA em placas gráficas NVIDIA
Acesso ao Processamento Paralelo
Visão geral da seção: Fabio Akita destaca como o acesso ao mundo do processamento paralelo começou a ser disponibilizado para programadores há pouco mais de uma década.
Acesso ao processamento paralelo
- Disponibilidade do acesso ao processamento paralelo para programadores
- Mudanças na última década
Evolução dos Computadores
Visão geral da seção: Fabio Akita resume a evolução dos computadores desde os anos 50 até os dias atuais, destacando as mudanças significativas no poder de processamento e capacidade de memória.
Evolução dos computadores
- Máquinas antigas e suas limitações
- Avanços em poder de processamento e capacidade de memória
IBM 701 e Cartões Perfurados
Visão geral da seção: Fabio Akita menciona o IBM 701, uma máquina antiga que utilizava cartões perfurados para carregar programas. Ele destaca as limitações dessas máquinas em termos de potência e capacidade de armazenamento.
IBM 701 e cartões perfurados
- Limitações do IBM 701 em termos de potência e capacidade de armazenamento
Eficiência no Uso das Máquinas Antigas
Visão geral da seção: Fabio Akita explora como os programadores buscavam utilizar eficientemente as máquinas antigas, organizando seus programas em batches para aproveitar as pausas durante a leitura ou gravação nas fitas magnéticas.
Eficiência no uso das máquinas antigas
- Organização dos programas em batches para aproveitar pausas nas operações de leitura e gravação
Programação em Batch
Visão geral da seção: Fabio Akita descreve o conceito de programação em batch, onde os programadores organizavam seus jobs em filas para serem processados durante a noite. Ele destaca a importância de escrever programas precisos e sem erros nesse contexto.
Programação em batch
- Organização dos jobs em filas para processamento noturno
- Importância de programas precisos e sem erros
Conceito de Concorrência
Visão geral da seção: Fabio Akita introduz o conceito básico de concorrência, explorando a ideia de permitir que múltiplos programadores trabalhem simultaneamente no mesmo computador, aproveitando as pausas do sistema.
Conceito básico de concorrência
- Utilização das pausas do sistema para permitir trabalho simultâneo
Evolução dos Conceitos de Eficiência
Visão geral da seção: Fabio Akita menciona os esforços feitos por grandes nomes da computação, como John Backus e John McCarthy, para aumentar a eficiência dos programadores. Eles propuseram utilizar as ineficiências do computador para permitir que múltiplos programadores trabalhassem concorrentemente.
Evolução dos conceitos de eficiência
- Proposta de utilizar as ineficiências do computador para permitir trabalho concorrente
Time-Sharing and Multi-Tasking New Section
This section discusses the concepts of time-sharing and multi-tasking in computer systems. It explains how these concepts evolved over time and their implementation in different types of computers.
Evolution of Time-Sharing and Multi-Tasking
- Time-sharing was initially used in mainframes and mini-computers in the corporate world during the 1960s to 1970s.
- In the 1980s, time-sharing started appearing in UNIX-based workstations.
- In the 1990s, time-sharing became prevalent in desktop computers.
Single-Core CPUs and Limited Task Execution
- Early microcomputers with CPUs like Z80, Motorola 68000, or Intel 8088 were single-core processors that could only execute one instruction at a time.
- These computers could only perform one task or job at a time. Users had to exit one program before loading another.
Cooperative Multi-Tasking
- Windows 3.1 introduced cooperative multi-tasking, where programs had to cooperate for others to run.
- If a program blocked the system (e.g., printing), other programs were unable to run until it finished.
Preemptive Multi-Tasking
- Modern operating systems like OS/2, Windows 95/NT, and Linux introduced preemptive multi-tasking.
- The operating system scheduler allocates time slices for each program/process to run before switching to another.
Introduction of Threads for Parallel Execution
- Threads allow parallel execution within a process.
- Threads can access the same memory space and work on shared resources.
- In single-core processors, threads are paused to allow others to run, simulating parallel execution.
Multi-Core Processors for True Parallelism
- Modern processors like Intel i3 have multiple cores, allowing true parallel execution of threads.
- Independent processes can run 100% in parallel on separate cores.
Memory Protection and Process Isolation New Section
This section explains the concepts of memory protection and process isolation in computer systems. It discusses how modern operating systems ensure that one program cannot overwrite the memory of another program.
Memory Protection
- Modern operating systems provide memory protection to prevent programs from writing over each other's memory.
- Each process is allocated a protected memory space where other programs cannot write.
Process Isolation
- Processes are isolated from each other, running in their own protected memory spaces.
- The operating system scheduler manages context switching between processes, allowing them to execute independently.
Multi-Threading and Parallel Processing New Section
This section explores multi-threading and parallel processing concepts in computer systems. It explains how multiple threads within a process can work simultaneously and how multi-core processors enable true parallelism.
Multi-Threading within a Process
- Multiple threads within a process can work simultaneously on shared resources.
- Threads can access the same memory space as the process they belong to.
Parallel Processing with Multi-Core CPUs
- Multi-core processors allow true parallel execution of threads.
- Independent processes can run 100% in parallel on separate cores.
Conclusion New Section
This section concludes the discussion on time-sharing, multi-tasking, memory protection, process isolation, multi-threading, and parallel processing. It highlights the evolution of these concepts and their significance in modern computer systems.
Key Takeaways
- Time-sharing and multi-tasking allow multiple programs to run concurrently.
- Preemptive multi-tasking ensures fair allocation of CPU time among programs.
- Memory protection prevents one program from overwriting another's memory.
- Process isolation provides a protected memory space for each program.
- Multi-threading enables parallel execution within a process.
- Multi-core processors allow true parallelism by running threads independently on separate cores.
Trabalhando com Multi-threading
Nesta seção, o palestrante discute os desafios de trabalhar com multi-threading e como a falta de sincronização pode levar a resultados inesperados ou não-determinísticos.
Problemas de compartilhamento de recursos
- Quando várias threads tentam escrever em um recurso compartilhado simultaneamente, podem ocorrer problemas de mistura de dados.
- A falta de sincronização pode levar a condições de corrida, onde as threads competem pelo acesso ao recurso.
- O bloqueio (lock) ou mutex é usado para sinalizar exclusividade no acesso ao recurso compartilhado.
Deadlocks e race conditions
- Se duas threads bloquearem recursos que a outra precisa, pode ocorrer um impasse (deadlock).
- Uma race condition pode ocorrer quando as threads não sinalizam corretamente que terminaram o uso do recurso.
- É importante entender esses conceitos para evitar resultados inesperados ao programar com multi-threading.
Threads e CPUs
Nesta seção, o palestrante explora como as threads são executadas nas CPUs e como o contexto das threads é trocado durante a execução.
Execução paralela em CPUs
- As CPUs modernas são projetadas para executar threads independentemente em paralelo.
- Cada thread possui seu próprio contexto e sequência de instruções.
- O contexto da thread é armazenado nos registradores da CPU durante uma troca de contexto.
Limitações do número de threads
- A troca de contexto entre as threads tem um custo, pois envolve a transferência de material de trabalho.
- Quanto mais threads são executadas em um único core, mais lenta será a execução geral.
- O ideal é ter o mesmo número de threads que o número de cores da CPU para obter uma execução eficiente.
Threads e Recursos Compartilhados
Nesta seção, o palestrante discute os desafios de trabalhar com recursos compartilhados entre threads e como determinar o número ideal de threads para uma máquina específica.
Desafios do compartilhamento de recursos
- Ao compartilhar recursos entre as threads, é necessário gerenciar corretamente o acesso exclusivo aos mesmos.
- A criação excessiva de threads pode levar a problemas como race conditions e deadlocks.
- Determinar o número ideal de threads depende do tipo de recurso compartilhado e requer tentativa e erro.
Troca entre processos e threads
- Criar processos é mais custoso para o sistema operacional do que criar threads.
- Em sistemas Linux, fazer forks (criação rápida de cópias) é mais eficiente do que em sistemas Windows.
- No desenvolvimento em Windows, recomenda-se criar um único processo por aplicação e usar várias threads dentro desse processo.
Criação de Processos vs. Criação de Threads
Nesta seção, o palestrante compara a criação de processos com a criação de threads e destaca as vantagens e desvantagens associadas a cada abordagem.
Custos da criação de processos
- Criar processos envolve carregar o binário do programa, alocar memória e verificar permissões de segurança.
- O procedimento de criação de processos é mais rápido em sistemas Linux do que em MacOS e Windows.
Vantagens das threads
- A criação de threads é mais barata do que a criação de processos, pois as threads compartilham a memória interna do processo.
- As threads permitem uma execução concorrente dentro do mesmo processo, mas exigem sincronização adequada para evitar problemas.
Escolhendo entre Processos e Threads
Nesta seção, o palestrante discute a escolha entre o uso de processos ou threads com base nas necessidades específicas da aplicação e no sistema operacional utilizado.
Troca entre processos e threads
- A escolha entre processos e threads depende das características da aplicação e das diferenças nos sistemas operacionais.
- Em geral, criar um único processo por aplicação e usar várias threads dentro desse processo é recomendado para maximizar a eficiência.
- No entanto, é importante considerar os custos associados à criação de processos e garantir uma sincronização adequada ao usar threads.
Threads vs Processes
This section discusses the advantages and disadvantages of using threads and processes in programming.
Threads vs Processes
- Threads are faster to create and use fewer resources compared to forking processes.
- However, managing mutexes and other manual tasks with threads can lead to more bugs and non-deterministic situations.
- Some argue that processes are infinitely easier to program due to their lower bug count.
- In practice, Linux and UNIX-based systems tend to have more solutions based on process forking, while Windows favors multi-threaded solutions.
- The best option may not always be the most obvious one.
Example of Multi-process Usage
This section provides an example of a web browser like Firefox or Chrome that uses multi-processes instead of threads.
Web Browsers as Examples
- Web browsers like Firefox or Chrome utilize multi-processes due to the heavy memory consumption caused by multiple tabs.
- Initially, browsers could only open one page at a time, but with the introduction of tabs, each tab became a potential thread.
- While this approach reduces resource usage, it also increases the number of bugs exponentially as threads within a process have access to everything in that process.
- Bugs in one thread can destabilize the entire browser, leading to crashes and data loss.
Separating Parts into Independent Processes
This section explains how some browsers started separating certain parts into independent processes for stability reasons.
Separating Browser Components into Processes
- Browsers like Safari initially separated components like Flash and Java into separate processes while keeping other parts as threads to minimize memory usage.
- Google Chrome took a different approach by completely separating each tab into its own process. This significantly improved stability.
- Chrome's separate processes can be seen in the Task Manager, allowing users to manually kill a process if needed.
- However, this separation also contributes to Chrome's high RAM usage.
Forking Processes and Copy-on-Write
This section discusses the concept of forking processes and copy-on-write in Linux.
Forking Processes and Copy-on-Write
- Forking a process involves pausing it and creating a copy of its memory in an isolated space. Both processes then have independent lives.
- In Linux, there is a feature called copy-on-write (CoW), where the second process uses minimal additional memory by pointing to the original process's memory.
- If the memory is not modified, both processes can reuse the same data instead of making unnecessary copies.
- Windows, on the other hand, duplicates memory when forking processes, making process creation more resource-intensive.
Threads vs Processes in Linux
This section compares threads and processes in Linux.
Threads vs Processes in Linux
- In Linux, each process created through forking has access to a copy of the parent process's memory. There is no need for mutexes or access control since each process has its own memory copy.
- Unlike threads within a single process that share everything, separate processes simplify programming by avoiding shared memory issues.
- However, threads are still lighter and use less total memory compared to multiple processes.
Evolution of Linux
This section highlights how Linux has evolved over time while maintaining compatibility with POSIX standards.
Evolution of Linux
- The interface and APIs of Linux have remained similar over time due to adherence to POSIX standards for portability between UNIX-based systems.
- LinuxThreads, implemented years ago, provided the abstraction of POSIX threads (pthreads) but had some bugs.
- Linux has undergone significant changes from the 1990s to the 2000s and continues to evolve.
Native Posix Thread Library (NPTL)
NPTL, developed by Ulrich Drapper and Ingo Molnár, is a one-to-one thread implementation that fixed the flaws of LinuxThreads. It was simpler to implement compared to NGPT, which was an M-to-N implementation. The NPTL project improved the performance of threads in Linux.
- The NPTL project won over NGPT and other implementations.
- NPTL is a one-to-one thread implementation, making it simpler than the M-to-N approach.
- It fixed the issues with LinuxThreads and significantly improved thread performance in Linux.
Different Thread Strategies in Unix
Different Unix systems had different strategies for implementing threads. Solaris used an M-to-N strategy until Solaris 9, while FreeBSD and NetBSD also used M-to-N initially but may have transitioned to a one-to-one approach later on.
- Solaris used an M-to-N strategy until Solaris 9.
- FreeBSD and NetBSD also initially used an M-to-N strategy.
- The transition from M-to-N to one-to-one started gaining traction in FreeBSD.
Challenges with Thread Scheduling
Thread scheduling involves various strategies that a scheduler can adopt. A supervisor manages the allocation of resources among threads. However, if not done efficiently, it can lead to inefficiencies such as idle threads occupying resources or interrupting critical tasks.
- An inefficient scheduler may allocate resources to idle threads or interrupt critical tasks unnecessarily.
- Adding more tables (resources) complicates the process of allocating work efficiently.
- Transporting work between tables slows down the overall process.
Impact of Scheduler Efficiency on Performance
The efficiency of the scheduler has a significant impact on system performance. A poor scheduler can result in video and audio playback issues, as well as hinder the smooth execution of tasks.
- Inefficient schedulers can cause video and audio playback issues.
- The Completely Fair Scheduler (CFS) introduced in Kernel 2.6 improved Linux's scheduling algorithm.
- Different operating systems prioritize different aspects and use different scheduling algorithms.
Completely Fair Scheduler (CFS)
The Completely Fair Scheduler (CFS), developed by Ingo Molnár, maximizes CPU utilization and prioritizes interactive programs. It was inspired by Con Kolivas' ideas and significantly improved Linux's thread management.
- CFS maximizes CPU usage and gives priority to interactive programs.
- It was developed by Ingo Molnár, inspired by Con Kolivas' ideas.
- CFS greatly improved Linux's thread management, especially for multimedia applications.
Differences in Thread Management among Operating Systems
Different operating systems implement different strategies for thread management. MacOS has been considered superior in multimedia creation due to its efficient thread management, while Windows took longer to reach a similar level of granularity.
- MacOS has always been known for its superior thread management in multimedia creation.
- Windows took years to catch up with MacOS in terms of thread management.
- Linux started improving significantly after the introduction of the CFS in 2007.
Importance of Processes in Linux
Despite improvements in thread management, processes continued to play an important role in Linux due to historical reasons and certain limitations.
- Even with advancements in thread management, processes remained important in Linux.
- Historical reasons and limitations contributed to the continued significance of processes.
The C10K Problem and Strategies for Handling Concurrent Connections
The C10K problem, discussed in a paper by Dan Kegel, addressed the challenge of serving a large number of concurrent connections. Various strategies were developed to handle this issue effectively.
- The C10K problem refers to the challenge of handling 10,000 concurrent connections.
- Servers today can handle millions of simultaneous connections.
- Different strategies exist for efficiently managing concurrent connections.
Importance of I/O in Handling Concurrent Connections
Input/output (I/O) plays a crucial role in handling concurrent connections. Efficient I/O management is essential for preventing bottlenecks and ensuring smooth operation.
- I/O encompasses various system inputs and outputs, such as files, network, USB devices, keyboard, and monitor.
- Efficient I/O management prevents bottlenecks and ensures smooth operation.
- Mainframes had to optimize I/O operations due to slower devices like tape drives.
Timestamps are approximate and may not be exact.
Trabalho de Escrever um Livro
Neste trecho, o palestrante fala sobre a analogia de escrever um livro com a colaboração de várias pessoas e como isso se relaciona com o bloqueio de recursos em sistemas compartilhados.
Colaboração na Escrita do Livro
- O trabalho de escrever um livro entre 500 pessoas é mencionado como exemplo.
- Cada pessoa escreve uma página, resultando em um livro completo no tempo que levaria para escrever apenas uma página.
- No entanto, se todas as pessoas tiverem que escrever no mesmo livro, apenas uma página pode ser escrita de cada vez.
Bloqueio de Recursos Compartilhados
- O conceito de locks em memória global do processo compartilhado entre múltiplas threads é mencionado.
- Quando as threads tentam acessar recursos restritos do sistema, ocorrem operações bloqueantes.
- Exemplos disso são operações que envolvem escrita em disco ou conexões de rede.
- Uma thread pode ficar bloqueada até que a operação seja concluída, enquanto outra thread pode executar outras tarefas não dependentes do recurso bloqueado.
I/O Assíncrono
Nesta parte da palestra, o palestrante discute a implementação do I/O assíncrono nos sistemas operacionais e como ele permite que as threads continuem executando outras tarefas enquanto aguardam a conclusão das operações bloqueantes.
Implementação do I/O Assíncrono
- Os sistemas operacionais passaram a implementar o I/O assíncrono como uma alternativa ao bloqueio de threads durante operações de escrita em disco, conexões de rede, entre outras.
- Em vez de bloquear a thread, o sistema operacional permite que ela solicite a operação e indique uma função para ser executada quando a operação for concluída.
- A programação se torna dependente do evento de término da operação de I/O, seja leitura ou escrita.
Programação Orientada a Eventos
- A programação orientada a eventos não é algo novo e já era utilizada em linguagens de programação dos anos 90 para aplicativos gráficos.
- Exemplos disso são os eventos de clique em um botão ou arrastar uma janela.
- Nos sistemas Linux, é possível enviar sinais para um processo como forma rudimentar de comunicação interprocessos.
Alternativas ao I/O Assíncrono
Nesta parte da palestra, o palestrante discute as alternativas ao uso do I/O assíncrono para lidar com múltiplas conexões em servidores web.
Alternativas Antes do I/O Assíncrono
- Antes da implementação do I/O assíncrono nos sistemas operacionais, duas alternativas eram comuns:
- Cada nova conexão era servida por forks do processo servidor. Isso gerava um processo filho para cada nova requisição, o que consumia muitos recursos.
- Cada nova conexão era servida por uma nova thread dentro do processo servidor. Embora as threads fossem mais leves que os processos, havia problemas de gerenciamento de memória compartilhada e possíveis bugs, como race conditions e deadlocks.
Limitações das Alternativas Anteriores
- O uso de forks ou threads para cada nova conexão em servidores web com milhares de conexões simultâneas era pesado e consumia muitos recursos do sistema operacional.
- O contexto switching entre threads também não era simples nem barato, exigindo um scheduler eficiente.
- Versões subsequentes do Apache e outros servidores web utilizaram threads para lidar com mais conexões, mas ainda havia limitações.
O NGINX e o I/O Assíncrono
Nesta parte da palestra, o palestrante fala sobre o projeto do servidor web NGINX, que utiliza uma combinação de processos e chamadas de I/O assíncrono para lidar com um grande número de conexões simultâneas.
O Projeto NGINX
- O NGINX é um servidor web desenvolvido por Igor Sysoev a partir de 2002, com lançamento da versão estável em 2004.
- Ele utiliza uma arquitetura que consiste em um processo master que carrega outros processos chamados "workers".
- Cada worker é capaz de gerenciar milhares de sockets de conexões simultâneas usando chamadas de I/O assíncrono.
- Em vez de criar forks ou threads para cada nova conexão, o NGINX registra as requisições via epoll no Linux e implementa um loop de eventos.
O modelo antigo de I/O bloqueante
Neste trecho, o palestrante explica como o modelo antigo de I/O bloqueante pode levar a um tempo de resposta lento para atender várias requisições simultâneas.
Problemas do modelo antigo de I/O bloqueante
- No modelo antigo, cada cliente precisa esperar que a requisição anterior seja concluída antes de fazer sua própria requisição.
- Isso resulta em um tempo de resposta lento quando há várias requisições simultâneas.
- O processo é semelhante a todos os clientes pedindo diretamente ao chef em um restaurante lotado, onde cada cliente precisa esperar pelo prato do cliente anterior antes de fazer seu pedido.
A solução com I/O assíncrono
Nesta parte, o palestrante introduz a solução com I/O assíncrono e compara com o modelo antigo.
Vantagens do I/O assíncrono
- Com o uso do I/O assíncrono, as requisições podem ser atendidas mais rapidamente.
- Os clientes fazem seus pedidos para um garçom e podem se sentar enquanto aguardam.
- O último cliente da fila é atendido mais rapidamente porque não precisa esperar por todos os clientes anteriores terem seus pratos prontos.
- O garçom passa os pedidos para o chef à medida que ficam prontos.
NGINX e sua arquitetura com workers
Nesta parte, o palestrante fala sobre a arquitetura do NGINX e como ele lida com várias conexões simultâneas.
Arquitetura do NGINX
- O NGINX utiliza uma arquitetura em que cada worker é uma única thread.
- O número de workers é determinado pelo número de cores disponíveis na CPU.
- Cada worker possui um loop de eventos que aguarda o término das requisições de I/O.
- O NGINX pode servir milhões de conexões simultaneamente, sem a necessidade de criar uma thread por conexão.
Capacidade do NGINX e uso de I/O assíncrono
Nesta parte, o palestrante fala sobre a capacidade do NGINX em lidar com um grande número de conexões simultâneas usando I/O assíncrono.
Capacidade do NGINX
- Um servidor NGINX em um bom hardware pode servir até milhões de conexões simultâneas.
- Isso é especialmente eficiente para servir conteúdos simples, como páginas HTML estáticas.
- O uso de I/O assíncrono permite que o servidor não perca tempo e recursos com context switching.
Twisted: outro framework com I/O assíncrono
Nesta parte, o palestrante menciona o framework Twisted, implementado em Python, que também utiliza I/O assíncrono.
Twisted e seu padrão Reactor
- Em 2002, o framework Twisted implementou o padrão Reactor com um event loop e uso de I/O assíncrono.
- Assim como o NGINX, ele permite atender várias requisições simultaneamente.
- O Twisted introduziu o conceito de Deferreds ou Futures, que serão explicados em episódios futuros.
Concorrência e paralelismo
Nesta parte, o palestrante aborda os conceitos de concorrência e paralelismo, além de mencionar a evolução dos sistemas para lidar com esses problemas.
Concorrência e paralelismo
- Antes dos anos 90, os computadores permitiam tarefas concorrentes, mas não necessariamente paralelas.
- A partir do surgimento de CPUs com múltiplos cores, tornou-se possível ter verdadeiro paralelismo.
- É importante entender como os sistemas operacionais lidam com a concorrência e implementam threads de maneiras diferentes.
Diferentes formas de implementação de I/O assíncrono
Nesta parte, o palestrante destaca que diferentes sistemas operacionais implementam o I/O assíncrono de formas distintas.
Implementações variadas do I/O assíncrono
- Os sistemas operacionais têm diferentes formas de implementar o I/O assíncrono.
- No Linux, é possível escolher entre diferentes schedulers para casos específicos.
- É importante compreender as diferenças nas implementações do I/O assíncrono nos diversos sistemas operacionais.
Opções para lidar com concorrência
Nesta parte, o palestrante menciona que existem várias opções para lidar com a concorrência e destaca que cada problema requer uma solução diferente.
Diferentes opções para lidar com concorrência
- Forks de processos e multi-threads são opções válidas para lidar com a concorrência.
- O I/O assíncrono é apenas mais uma opção na caixa de ferramentas.
- Cada tipo de problema requer uma solução específica, e é importante explorar diferentes abordagens.
Evolução dos conceitos de Reactor
Nesta parte, o palestrante menciona que o padrão Reactor não nasceu apenas com o Node.js, mas já era implementado pelo NGINX e Twisted desde 2002.
Evolução dos conceitos do Reactor
- O padrão Reactor foi implementado pelo NGINX e Twisted em 2002.
- Esses conceitos já vinham sendo pesquisados há anos antes do surgimento do Node.js em 2009.
- Muitas inovações na área de concorrência surgiram principalmente na década de 2010.
Conclusão
O palestrante abordou os problemas do modelo antigo de I/O bloqueante e apresentou a solução com I/O assíncrono. Ele explicou como o NGINX utiliza essa abordagem para lidar com um grande número de conexões simultâneas. Além disso, mencionou o framework Twisted como outra opção que utiliza I/O assíncrono. Também foram discutidos os conceitos de concorrência e paralelismo, bem como as diferentes formas de implementação do I/O assíncrono nos sistemas operacionais. Por fim, destacou-se a importância de escolher a melhor abordagem para cada problema de concorrência.