{"id":20548004,"url":"https://github.com/aleroxac/goexpert-gointernals","last_synced_at":"2026-05-28T01:31:37.916Z","repository":{"id":245850209,"uuid":"816278047","full_name":"aleroxac/goexpert-gointernals","owner":"aleroxac","description":"goexpert-gointernals","archived":false,"fork":false,"pushed_at":"2024-07-02T11:48:47.000Z","size":29,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-06T05:23:36.832Z","etag":null,"topics":["fullcycle","go","go-internals","goexpert","golang"],"latest_commit_sha":null,"homepage":"https://github.com/aleroxac/goexpert-gointernals","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aleroxac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-17T12:15:01.000Z","updated_at":"2024-08-20T17:29:04.000Z","dependencies_parsed_at":"2024-06-27T16:19:01.058Z","dependency_job_id":"5d9f38f9-f820-431c-896a-3d3ceeb070b3","html_url":"https://github.com/aleroxac/goexpert-gointernals","commit_stats":null,"previous_names":["aleroxac/goexpert-gointernals"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aleroxac/goexpert-gointernals","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleroxac%2Fgoexpert-gointernals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleroxac%2Fgoexpert-gointernals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleroxac%2Fgoexpert-gointernals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleroxac%2Fgoexpert-gointernals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aleroxac","download_url":"https://codeload.github.com/aleroxac/goexpert-gointernals/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleroxac%2Fgoexpert-gointernals/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33590884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fullcycle","go","go-internals","goexpert","golang"],"created_at":"2024-11-16T02:11:37.953Z","updated_at":"2026-05-28T01:31:37.901Z","avatar_url":"https://github.com/aleroxac.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# goexpert-gointernals\n\n\n## Multitask - Timeline\n- 1940-1960: pré-multitask; programação via cartões perfurados, tarefa por tarefa\n- 1960-1970: sistemas de tempo compartilhado; multi-user, mainframes\n- 1980: os-multitask; unix\n- 1990-2000: hyper-threading; UI, processos e threads\n- 2000: multi-core; multiplos cores permitindo tasks simultaneas, paralelismo real\n- 2010: otimizações para nuvem, ia, etc: otimizações e especializações de tarefas\n\n\n\n## Processos\n- o que é um processo: instância de um programa em execução\n- componentes de um processo:\n    - endereçamento: região da memória dedicada a um processo\n    - contextos:\n        - conjunto de dados que o SO salva para gerenciar um processo\n        - possui o endereço de memória da próxima instrução que o processador irá executar\n        - auxilia no context-switch\n    - registros do processador:\n        - áreas que temporarioamente armazenam no GPU dados e endereços para realizar a execução\n        - dados: exemplo=realiza operações aritméticas e lógicas\n        - registro de endereços:\n            - armazenamento em memória, incluindo stack pointers; exemplo=ao acessar uma variável o CPU possui um registro na memória para guardar seu valor\n    - heap:\n        - utilizado para alocação de memória dinâmica. Cresce e encolhe em tempo de execução conforme a necessidade de mais ou menos espaço\n    - stack:\n        - armazena informações de controle para chamadas de função, como endereços de retorno, e parâmetros de função\n        - segue uma estrutura LIFO(Last In, First Out - Último a entrar, primeiro a sair)\n    - registros de status/flags:\n        - fornecem os status recentes das operações realizadas pelo CPU\n        - trabalham atravéz de bits específicos(flags)\n            - ex: flag-zero(z): resultado de uma operação o qual o resultado é zero. Decide o fluxo do programa baseado nesse valor\n            - ex: flag-sigma(s) ou negative(n): indica o resultado de uma operação positiva ou negativa\n            - ex: flag-overview: produz resultado além da capacidade\n\n\n\n## Ciclo de vida de um processo\n### Creation\n- Um novo processo é criado quando um programa solicita a execução de um processo, por meio de chamadas de sistema como fork() no UNIX/Linux ou CreateProcess() no Windows\n### Execution\n- O processo está ativamente sendo executado pela CPU. Pode alterar entre os estados de \"executando\" e \"pronto\"(para ser executado)\n- Waiting/Blocked:\n    - o processo é suspenso e colocado em espera até que um evento externo ocorra. Comum em operações de I/O, onde o processo aguarda pelo término de uma leitura de disco ou recebimento de uma entrada de rede.\n- Termination: \n    - o processo completa sua execução ou é forçadamente terminado\n    - exit: conflusão bem-sucedida do processo após completar suas instruções\n    - killed: interrupção por meio de um erro de execução ou por ser terminado por outro processo(por exemplo, através do comando kill)\n\n\n\n## Criação de um novo processo no SO\n- unix/linux\n    - fork()\n    - clona o processo atual\n    - gerado um processo filho\n    - fork() retorna um valor diferente para o processo pai(PID)\n    - processo pai e filho são quase idênticos, porém os valores na memória são copiados para outro endereçamento separado e independente\n    - processo pai recebe um PID(valor inteiro positivo) do filho quando o fork() é chamado\n    - processo filho retornar o PID 0, indicando que é um processo filho\n\n\n\n## Gerenciamento de processos\n- scheduler\n    - decide qual processo será executado\n    - alterna entre processos\n    - possui diversos algoritmos para atentar maximizar o uso da CPU\n    - scheduper pode:\n        - selecionar processos de uma fila que estão \"ready queue\"\n        - alocar CPU: mudança de estado - ready to running\n        - retirar CPU: I/O, etc\n- tipos de schedulers\n    - colaborativo / cooperativo: processos que estão sendo executados tem controle quando liberam a CPU para outros processos\n        - contras: processos podem monipolizar a CPU\n    - preemptivo: SO tem a capacidade de interromper um processo em execução e ceder o uso da CPU para outro processo. Trabalha de forma mais \"justa\"\n        - contras: muitas mudanças de contexto\n\n\n\n## Threads\n- processos são instâncias de programs em execução\n- threads são unidades básicas de utilização de CPU que fazem parte dos processos\n- threads são sequências de execução dentro do mesmo processo, compartilhando o mesmo espaço de memória e recursos\n- dentro de um único processo, várias threads podem existir, cada uma executando diferentes partes do programa\n- paralelismo vs concorrência: com múltipos CPUs conseguimso atingir paralelismo. Com apenas um núcleo, trabalhamos de forma concorrente(simulando paralelismo)\n- threads, obviamente, ocupam menos espaço na memória do que um processo, pois elas compartilham a mesma memória do processo\n- cada thread possui sua stack indepentente e isolada\n- cada thread ocupa ~= 2MB(linux)\n- cada thread, no go, ocupa 2KB\n\n\n---\n\n\n## Runtime Architecture\n- goroutines = threads do go, também conhecidas como light-threads, green-threads, vitual-threads, etc\n- scheduler = scheduler do go; ajuda no agendamento da execução das goroutines\n- channels = para trabalhar de forma concorrente e possibilitar comunicação e sincronização entre treads(goroutines)\n- memory-allocation\n- garbage-collector\n- stack management\n- network-poller\n- reflection\n\n\n\n## Padrão M:N\n- Threads Virtuais(threads geradas pela linguagem de programação) vs Threads Reais(gerados pelo SO)\n- Modelo de agendamento de tarefas\n    - M: threads virtuais em \"user land, green threds, light threads\"\n    - N: threads reais do sistema operacional\n    - M tarefas para N threads\n\n\n\n## Goroutines\n- funções/métodos que são executadas de forma concorrente\n- são \"threads\" gerenciadas pelo runtime do go\n- muito mais \"baratas\" do que criar novas threads no sistema operacional(2KB)\n- muito mais rápido de criar e destruir\n- compartilham os mesmos endereços de memória do programa em go. Possuam stacks independentes\n\n\n\n## Padrão M:P:G\n- machine \u003c processor \u003e goroutine\n- quando o go inicia, ele cria as threads reais e \"gruda\" 1 processor por machine\n- em geral, será 1 processador lógico por machine\n- ao longo da execução do programa, novas threads reais podem ser criadas\n- o processador lógico é quem faz o link com a goroutine, e ele é quem fala com a thread real\n\n\n\n## runtime.GOMAXPROCS()\n- go cria um P(processor) por Núcleo Computacional\n- go tente a criar um M(Machine - Threads) para atribuir para cada P\n- o valor de uma Machine por processor não é fixo\n    - go pode criar mais threads no SO se as atuais estiverem bloqueadas por I/O ou outro motivo de executar as Goroutines\n    - o objetivo é sempre manter os Ps ocupados, sem tempo ocioso\n\n\n\n## Scheduler: Pool de Ps\n- gestão de como e quando as tarefas são executadas em threas do sistema operacional\n- decide qual tarefa deve ser executada em qual thread e em que momento\n- gerencia o balanceamento de carga entre diferentes threads ou processadores lógicos, garantindo que nenhuma thread fique sobrecarregada enquanto outras estão ociosas\n- gerencia questões como sincronização, mutex, racing conditions, deadlocks, etc\n\n\n\n## Scheduler no Go\n- o trabalho do Scheduler é combinar em G(o código a ser executado), um M(onde executá-lo) e um P(os direitos e recursos para executá-lo).\n- quando um M para de executar um código Go do usuário, por exemplo, ao entrrar em uma syscall, ele devolve seu P para o pool de P ociosos.\n- para retomar a execução do código Go do usuário, por exemplo, ao retornar de uma syscall, ele deve adquirir um P do pool de ociosos.\n- https://go.dev/src/runtime/HACKING\n- detalhamento\n    - scheduler faz parte do runtime. Trabalha de forma adaptativa\n        - atribuição de tarefas\n        - balanciamento de carga\n        - gerenciamento de concorrência\n    - trabalha de forma não cooperativa com preempção(versão \u003e= 1.14)\n\n\n\n## Scheduler no Go vs Goroutines\n- scheduler determina o estado de cada goroutine\n    - running\n    - runnable(fila)\n    - not runnable(bloqueada fazendo I/O, por exemplo)\n- work stealing\n    - se o P está ocioso(idle)\n    - ele rouba goroutines de outro P ou mesmo da fila global de goroutines\n        - verifica 1/61 do tempo, evitando overhead para evitar buscar na fila global o tempo todo\n\n\n\n## Preempção no Go\n- sinalização de preempção\n    - nivel de sistema\n        - go insere pontos de premepção usando recursos do SO(exemplo: signals)\n    - verificação de pontos onde as goroutines podem ser seguramente interrompidas\n        - localizados em funções que são chamadas de forma frequente / loops\n    - funções longas\n        - se uma função está sendo executada sem chamar outras funções ou fazendo I/O por muito tempo, ela está desafiando o scheduler. Logo, o go internamente vai realizar a preempção mesmo sem ter os pontos de sinalizadores\n\n\n\n## Memória\n### Conceitos básicos\n- memória de acesso rápido; memória que fica no chip da CPU, utilizada como cache\n    - l1: 64kb\n    - l2: 0.5mb\n    - l3: 8mb\n- memória de acesso lento\n    - DDR(double data rate); clock consegue ter acesso 2 vezes por ciclo\n    - é ligada através de um barramento(canais de comunicação entre CPu e a memória)\n- endereços de memória são referenciados em formato hexadecimal(de 0-9 e de A-F)\n### Custo de memória\n- threads, obviamente, ocupam menos espaço na memória do que um processo, pois elas compartilham a mesma memória do processo\n- cada thread possui sua stack independente e isolada\n- cada thread ocupa, em média, 2MB(linux)\n- stack \u003c heap \u003c static data \u003c literals \u003c instructions\n- function_c() \u003e function_b() \u003e function_a() \u003e free memory space\n### heap\n- dynamic memory allocation\n    - large memory pool; a heap pega um bloco de memória para si, que é muito maior do que a stack\n    - flexibilidede; possibilitando organizar informações em diversos locais de memória\n    - acessível globalmente\n    - reutilizável\n    - suporta estruturas complexas\n    - gerenciamento completo\n    - leaks\n    - fragmentação; buracos nos blocos de memória causados durante processos de alocação e desalocação\n    - mais lento que a stack\n    - concorrência\n### Fragmentação\n- falsa sensação de que existe o espaço necessário na memória, mas quando temos blocos de dados maiores e que precisam ficar juntos, percebemos que não temos esse espaço\n- arenas\n    - blocos de espaço em memória, uma separação lógica para execução alguma tarefa; também possibilitando fazer subdivisões\n    - subdivisão da heap em chunks\n        - por velocidade\n            - fast bin\n            - small bin\n            - large bin\n        - por tamanho\n            - 8KB\n            - 64KB\n            - \u003e1MB\n- alocadores\n    - alocadores mais populares\n        - malloc/free (C std library)\n        - dlmalloc(Doug Lea's Malloc) - Não suporta de forma eficiente Multithreading\n        - ptmalloc / ptmalloc2 (pthreads Malloc) - Utilização de arenas\n        - jemalloc (Jason Evans) - otimizado por Facebook, Rust, Postgres\n        - TCMalloc (Thread-Caching Malloc) - Google\n\n## Memória no Go\n- utiliza como baseo TCMalloc(desenvolvido pelo Google)\n  - ao longo do tempo, o alocador tomou diferentes caminhos do TCMalloc\n  - o próprio runtime do Go é responsável por trabalhar com a alocação de memória\n- nome do alocador é 'mallocgc'\n  - flow: G(goroutine) \u003e P(processor) \u003e mcache \u003e mcentral \u003e mheap \u003e OS\n  - tipos\n    - tiny: objetos \u003c 16 bytes\n    - small: objetos entr 16 e 32KB\n    - large: objetos \u003e 32KB\n  - gerenciamento de memória\n    - separa os chunks em spans, que são blocos de páginas da memória heap\n    - mheap[ N[spans] ] \u003e N[mcentral(gerencia spans de N diversos tamanhos)] \u003e N[mcache(cache local)]\n- garbage collector\n    - o garbage collector(GC) é um mecanismo automático de gerenciamento de memória que busca, identifica e libera memória que não está mais sendo utilizada pelo grograma. Isso é crucial para previnir vazamentos de memória e garantir a eficiência do uso de memória\n    - caracteristicas do GC do go:\n        - não-geracional: trata todos os objetos igualmente, sem distinção entre objetos novos e antigos\n        - concorrente: executa a maior parte do trabalho de coleta de lixo concorrentemente com a aplicação, minimizando as pausas\n        - baseado na técnica de \"Tri-color Mark and Sweep\": utiliza o algoritmo de marcação e varredura com tês cores(branco, cinza e preto) para gerenciar os objetos\n    - objetos alcançáveis\n        -  podem ser acessados direta ou indiretamente por referência em um ponto de entrada no programa\n            - roots: são os pontos de entrada iniciais para a busca de objetos alcançáveis. Incluem variáveis globais, variáveis locais atualmente ativas nas stacks de execução, e registros de CPU\n            - objetos referenciados: qualquer objeto que é referenciado direta ou indiretamente a partir de um objeto root\n        - exemplos\n            - 01\n                - se uma variável global referencia um objeto A, e o objeto A referencia um objeto B, então ambos os objetos A e B são alcançáveis\n            - 02\n                - uma variável global globalVar refenrecia o objeto A\n                - o objeto A referencia um objeto B\n                - o objeto B referencia um objeto C\n                - o objeto D não é referenciado por nenhum outro objeto\n                - A, B e C são alcançáveis porque podem ser acessados a partir da variável global globalVar. O objeto D é inalcançável porque não há nenhuma referência a ele a partir das raízes ou de outros objetos alcançáveis\n    - dinamica\n        - aplicação \u003e GC \u003e write barrier\u003e \n        - GC:\n            - 1. SWT(Stop the World): para a execução do programa para rodar o GC\n                - Write Barrier: intercepta e pausa todas as chamadas do programa\n                - Mark Setup\n            - 2. Marking Work(concurrent) - nesse momento o programa volta a ser executado, o resto do trabalho vai ser feito concorrentemente\n                - 25% do CPU é alocado para fazer o processo de marcação de objetos alcançáveis\n                - Mark Assist: pega outras goroutines para trabalhar junto com o GC para ajudar a fazer as marcações\n                    - branco: objeto ainda não explorado\n                    - cinza: objetos alcançáveis\n                        - pendentes de processamento\n                        - precisa buscar por referência\n                        - trabalha de forma recursiva\n                    - preto: objeto já explorado\n            - 3. Mark Termination: novamente interrompe a execução do programa e faz a varredura em busco de novos objetos alcançáveis\n                - finaliza a marcação\n                - desliga o Write Barrier\n            - Sweeping(Concorrente)\n                - identifica e libera a memória de objetos não alcançáveis\n                - varredura on-demand\n    - GOGC\n        - define o tamanho da heap quando o GC deve ser acionado\n        - por padrão é 100%\n        - exemplo\n            - se a heap após a última coleta de lixo for de 4MB e o GC Percentage estiver definido como 100%, o próximo GC será acionado quando o tamanho total do heap atingir 8MB(4MB + 100% disso, ou seja, mais 4MB, totalizando 8MB)\n        - quanto mais baixo o número, mais frequente sera ativado o GC\n        - GOGC=100 (variável de ambiente)\n    - GC Trace\n        ```\n        gc 1 @0.019s 0%:0.014+0.56+0.010 ms clock, 0.029+0/0.55/0+0.021 ms cpu, 4-\u003e4-\u003e1 MB, 5MB goal, 8 P\n        ```\n        - gc 1: numero do clico de GC\u003c começando em 1 para o primeiro GC que ocorre após a inicialização do programa\n        - @0.019s: o tempo desde o início do programa até o início deste ciclo de GC\n        - 0%: a porcentagem do tempo total do programa gasto em GC até este ponto\n        - 0.014+0.56+0.010 ms clock\n            - 0.014: antes da coleta - este valor indica o tempo gasto antes de iniciar efetivamente a fase concorrente de marcação(marking). Pode incluir preparações iniciais e o tempo para iniciar a coleta de lixo. O \"0.014ms\" sugere que foram gastos 14 microssegundos em atividades preliminares antes de iniciar a marcação propriamente dita.\n            - 0.56: fase concorrente - o valor \"0.56ms\" representa o tempo gasto na fase concorrente do GC\u003c que geralmente envolve a marcação(marking) de objetos alcançáveis no heap. Durante esta fase, o programa continua em execução normalmente. enquanto o GC trabalha para identificar quais objetos ainda estão sendo usados. Os 560 microssegundos indicam o tempo total despendido nessa atividade concorrente.\n            - 0.010: finalização da coleta - o \"0.010ms\" é o tempo gasto aós a fase concorrente, incluindo a finalização da marcação e a preparação para a fase de varredura(sweep). Esses 10 microssegundos podem cobrir a conclusão do trabalho de marcação e as atividades de limpesa necessárias antes de o GC prosseguir para a próxima etapa.\n        - 0.029+0/0.55/0+0.021 ms cpu\n            - 0.029+0: indica o tempo gasto na fase de STW_SWEEP_TERMINATION. \"0.029\" é o tempo de STW para esta fase, e o \"+0\" indica que não houve tempo adicional significativo gasto após a pausa inicial\n            - 0.55: tempo gasto na fase de marcação e varredura(MARK_AND_SWEEP) que é feita de forma concorrente, sem STW. \"0.55\" indica o tempo gasto nessa fase\n            - 0+0.021: tempo gasto na fase de STW_MARK_TERMINATION. \"0\" indica que não houve tempo inicial de STW sifnificativo antes dessa fase, e \"+0.021\" é o tempo de pausa STW para finalizar a marcação.\n        - 4-\u003e4-\u003e1 MB: tamanho do heap antes do GC, o tamanhho do heap ao determinar iniciar o GC, e o tamanho do heap após o GC, respectivamente\n        - 5MB goal: o tamanho alvo do heap para o próximo GC, baseado na heurística do GC para tentar manter o tempo de pausa ou a frequência do GC dentro de limites desejáveis\n        - 8P: número de processadores lógicos(P's) usados pelo Go scheduler\n\n        - clock-time: tempo total que o GC está tomando do ponto de vista de um observador externo. Isso inclui todos os aspectos de execução e espera. Tempo, do início ao fim\n        - cpu-time: tempo que a CPU está ativamente trabalhando no GC, excluindo tempos de espera ou quando outras goroutines estão sendo executadas\n\n        - histórico de melhorias do GC\n            - go 1.5: introdução do GC concorrente\n                - substitui o modelo de GC Stop-The-World(STW) por um modelo concorrente, reduzindo significativamente as pausas do GC e melhorando a performance geral das aplicações Go\n            - go 1.8: otimizações no GC\n                - redução das pausas do GC ao aprimorar a eficiência da fase de varredura(sweep) e da assistência de marcação(mark assist)\n            - go 1.14: implementação do Non-Cooperative Preemption\n                - embora não seja uma mudança no GC em si, essa otimização na preempção de goroutines teve impactos positivos na latência do GC, permitindo que o runtime interrompesse goroutines mais eficientemente para garantir que o GC pudesse rodar a tempo\n            - go 1.15 e 1.16: redução de alocações\n                - otimizações nessas versões reduziram as alocações descenessárias, diminuindo a pressão sobre o GC\n            - go 1.19: Soft Memory Limit\n                - introdução de um limite de memória \"soft\" para o GC, permitindo que os desenvolvedores definam um alvo de uso de memória que o GC tentará respeitar, melhorando a gestão da memória em sistemas com restrições\n\n\n\n## Channels no Go\n- channels são um mecanismo de comunicação e sincronização entre goroutines no Go. Eles permitem que goroutines troquem dados de maneira segura e eficiente, suportando a construção de programas concorrentes\n\n- o problema da não utilização de channels\n    - problemas de sincronização\n        - quando a G1 quer passar um valor para a G2, ela altera um valor na memória para a G2 ter acesso\n        - o grande problema é que outras goroutines e partes do programa também podem ter acesso aquele endereço de memória\n        - ou a G1 não terminou completamente de alocar o valor em memória e a G2 já fez a leitura e eventualmente uma gravação no mesmo local\n    - dificuldade de trabalhar com concorrência\n        - data race(race condition)\n        - para remediar o problema utilizamos Mutex(Mutual Exclusion)\n            - fazemos um lock no valor na memória e durante esse momento, somente uma goroutine pode fazer alteração. Após isso, esse valor é liberado(unlock)\n            - mutex e similares abrem muita marge para erro, pois tudo isso é feito de forma manual\n    - deadlocks\n        - quando uma goroutine-2 quer acessar algum dado bloqueado na goroutine-1, e a goroutine-1 quer acessar algum dado bloqueado pela goroutine-2, onde acontece o cenário do programa ficar indefinidamente bloqueado nessas 2 goroutines\n\n- a frase que define com mais clareza a utilização de channels\n    - \"Do not communicate by sharing memory; instead, share memory by communicating\"\n        - essa frase encapsula um dos princípios fundamentais do design de sistemas concorrentes no Go. A ideia é que, ao usar channels para comunicação entre goroutines, você evita muitos dos problemas associados à concorrência e ao compartilhamento de memória direta, como condições de corrida e deadlocks\n        - em vez de várias goroutines acessarem diretamente variáveis compartilhadas(o que requer mecanismos de sincronização como locks), elas se comunicam enviando dados através de channels, o que proporciona uma maneira segura e clara de coordenar o acesso aos dados\n\n- channels são um mecanismo fundamental de comunicação entre goroutines, permitindo a troca segura e sincronizada de dados\n- eles são utilizados para passar informações entre goroutines de forma eficiente, evitando a necessidade de locks explícitos e reduzindo a complexidade da sincronização\n\n- tipos de channels\n    - não-bufferizados: requerem que a operação de envio e recebimento ocorra simultaneamente. Ideal para sincronização direta entre goroutines\n    - bufferizados: permitem que dados sejam armazenados temporariamente no buffer, permitindo que a goroutine de envio ea de recebimento sejam executadas em tempos diferentes\n\n- estrutura interna de um channel\n``` go\ntype hchan struct {\n    qcount      // total de dados na fila\n    dataqsize   // tamanho da fila circular(buffer)\n    buf         // ponteiro para o array de elementos no buffer\n    elemsize    // tamanho de cada elemento\n    closed      // flag indicando se o channel está fechado\n    sendx       // indice de envio\n    recvx       // indice de recebimento\n    recvq       // fila de goroutines esperando para receber\n    sendq       // fila de goroutines esperando para enviar\n    lock        // mutex para sincronização\n}\n```\n\n- dinâmica de funcionamento\n```\ng1(envio) \u003e \n    lock \u003e \n        checa espaço no buffer \u003e \n            buffer está cheio? \u003e \n                sim \u003e adiciona a sendq(block)\n                não \u003e coloca nop fuffer na posição sendx \u003e incrementa sendx \u003e libera o lock\n\ng2(recebimento) \u003e \n    lock \u003e \n        verifica dados no buffer \u003e\n            buffer vazio \u003e\n                sim \u003e adiciona a recvq(block) - aguardando dados\n                não \u003e retira do buffer na posição recvx \u003e incrementa recvx \u003e libera o lock\n\ng3(fechamento do canal)\n    lock \u003e \n        set flag closed \u003e\n            notifica goroutines recvq \u003e \n                libera o lock\n```\n\n- channels bufferizados\n    - altas taxas de produção e consumo\n        - quando há uma diferença significativa nas taxas de produção e consumo de dados entre goroutines, channels não-bufferizados podem causar gargalos\n        - exemplo: se uma goroutine está gerando dados muito mais rápido do que outra pode consumir, a goroutine produtora ficará frequentemente bloqueada esperando que a consumidora esteja pronta para receber, resultando em desempenho ineficiente\n    - pipeline de processamento\n        - em pipelines de processamento de dados, onde os dados passam por várias etapas, cada uma implementada como uma goroutine, o uso de channels não bufferizados pode causar bloqueios frequentes, dificultando o fluxo suave dos dados através do pipeline\n        - exemplo: se uma goroutine está gerando dados muito mais rápido do que outra pode consumir, a goroutine produtora ficará frequentemente bloqueada esperando que a consumidora esteja pronta para receber, resultando em desempenho ineficiente\n    - tarefas assíncronas\n        - quando se trabalha com tarefas que não precisam ser sincronizadas estritamente, como registros de logs ou coleta de métricas, usar channels não-bufferizados pode introduzir latência descenecessária\n        - exemplo: ao registrar logs em um servidor de alta carga, esperar que cada log seja processado antes de prosseguir pode impactar negativamente a performance. Um channel bufferizado permite que a produção de logs continue sem esperar pelo processamento de cada mensagem de log\n    - comunicaçào entre múltiplas goroutines\n        - quando há comunicação entre várias goroutines produtoras e consumidoras, channels não-bufferizados podem aumentar a contenção e reduzir a paralelização efetiva\n        - exemplo: se várias goroutines tentam enviar dados para um único channel não-bufferizado, elas competirão pelo acesso, resultando em bloqueios frequentes e menor desempenho\n    - operações de I/O\n        - em operações de I/O, onde o tempo de espera pode ser significativo, o uso de channels não-bufferizados pode levar a bloqueios desnecessários\n        - exemplo: uma goroutine que lê dados de um arquivo e outra que escreve esses dados em uma rede. Se a escrita na rede for mais lenta, a leitura do arquivo será bloqueada frequentemente\n\n- channels não-bufferizados\n    - sincronização estrita\n        - quando é necessário garantir que a propdução e o consumo de dado ocorrem de maneira sincronizada, channels não-bufferizados são ideais. Eles garantem que cada operação de envio seja emparelhada diretamente em uma operação de recebimento\n        ``` go\n            package main\n            \n            import \"fmt\"\n\n            func main() {\n                done := make(chan bool)\n\n                go func() {\n                    fmt.Println(\"Goroutine: Working...\")\n                    done \u003c- true // Sinaliza que a goroutine terminou o trabalho\n                }()\n\n                \u003c- done // Espera a goroutine terminar\n                fmt.Println(\"Main: Goroutine completed\")\n            }\n        ```\n    - handshake\n        - em situações onde duas goroutines precisam trocar informações ou confirmar que uma ação foi realizada antes de prosseguir, channels não-bufferizados fornecem um mecanismo simples e seguro\n        ``` go\n            package main\n            \n            import \"fmt\"\n\n            func main() {\n                start := make(chan bool)\n\n                go func() {\n                    fmt.Println(\"Goroutine: Initializing...\")\n                    start \u003c- true // Sinaliza que a inicialização está completa\n                }()\n\n                \u003c- done // Espera a inicializaçào\n                fmt.Println(\"Main: Initialization completed\")\n            }\n        ```\n    - eventos temporizados\n        -  quando você precisa lidar com eventos temporizados, como timeouts, channels não-bufferizados podem ser usados em conjunto com o select para implementar timeouts de maneira simples e eficaz\n         ``` go\n            package main \n\n            import (\n                \"fmt\"\n                \"time\"\n            )\n\n            func main() {\n                ch := make(chan int)\n                \n                go func() {\n                    time.Sleep(2 * time.Second)\n                    ch \u003c- 42\n                }()\n\n                select {\n                case val := \u003c-ch:\n                    fmt.Println(\"Received:\", val)\n                case \u003c-time.After(1 * time.Second):\n                    fmt.Println(\"Timeout\")\n                }\n            }\n         ```\n    - coordenar finalização\n        - quando várias goroutines precisam ser coordenadas para garantir que todas elas completem antes que o programa possa prosseguir, channels não-bufferizados podem ser utilizados para sinalizar a conclusão\n        ``` go\n            package main\n\n            import \"fmt\"\n\n            func main() {\n                done := make(chan bool)\n                numWorkers := 3\n\n                for i := 0; i \u003c numWorkers; i++ {\n                    go func(id int) {\n                        fmt.Printf(\"Worker %d: Working...\\n\", id)\n                        done \u003c- true // Sinaliza que a goroutine terminou o trabalho\n                    }(i)\n                }\n\n                for i := 0; i \u003c numWorkers; i++ {\n                    \u003c-done // Espera cada goroutine terminar\n                }\n\n                fmt.Println(\"All worker completed\")\n            }\n        ```\n\n- parametrização do tamanho do buffer\n    - taxa de produção e consumo\n        - taxa variável: se a taxa de produção e consumo varia significativamente, um buffer maior pode ajudar a suavizar as diferenças e evitar bloqueios frequentes\n        - taxa constante: se as taxas de produção e consumo são constantes e iguais, um buffer menor pode ser suficiente\n    - latência e desempenho\n        - baixa latência: se a latência é crítica, um buffer menor pode ser preferível para garantir que os dados sejam processados rapidamente\n        - alto desempenho: um buffer maior pode ajudar a aumentar o desempenho em sistemas de alta taxa de transferência, reduzindo a contenção entre goroutines\n    - memória disponível\n        - uso de memória: buffers grandes consomem mais memória. Certifique-se de que há memória suficiente disponível e considere o impactor no uso geral do sistema\n    - padronização de pipelines\n        - etapas de pipeline: se você está construindo um pipeline de processamento, cada etapa pode se beneficiar de um buffer que permite processar dados em lotes, melhorando a eficiência geral\n    - resumo\n        - não há um tamanho de buffer único que seja ideal para todos os casos. A escolha do tamanho do buffer deve ser baseada em:\n            - taxa de produção e consumo\n            - requisitos de latência e desempenho\n            - memória disponível\n            - características específicas do seu pipeline de processamento\n            - monitorar e ajustar o tamanho do buffer conforme necessário, juntamente com testes de desempenho, pode ajudar a encontrar o equilíbrio certo para seu caso de uso específico\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleroxac%2Fgoexpert-gointernals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faleroxac%2Fgoexpert-gointernals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleroxac%2Fgoexpert-gointernals/lists"}