Descubra o poder da programação concorrente com a linguagem Go
O mundo da tecnologia se encontra em uma constante corrida: a corrida das tecnologias,das ferramentas, das linguagens de programação. Novos problemas vão surgindo e, com eles, novas demandas, novas formas de resolvê-los. Às vezes, até mesmo velhos problemas são surpreendidos com novas ferramentas. E, assim, vamos caminhando em busca da tecnologia perfeita.
Uma das demandas recorrentes no domínio do desenvolvimento de software é a questão da performance. A cada geração que passa, nossas peças físicas – o hardware – se tornam mais robustas. Placas de vídeo, processadores com múltiplos núcleos, memória… Mas algumas das nossas linguagens de programação não conseguem acompanhar em tempo real, ou simplesmente não têm a estrutura necessária para fazer um uso ótimo desses recursos. Daí nascem novas linguagens.
Processadores, núcleos, paralelismo, concorrência… Quê?
Com processadores que contam com cada vez mais núcleos e, portanto, poder de processamento, é mais do que desejável que nossos programas consigam usar tudo o que há disponível para maior velocidade e performance e, com isso, tornar a experiência do usuário melhor. Em pleno 2022, nós humanos queremos as informações rapidamente e nossos sistemas ágeis, e é por isso que nós desenvolvedores fazemos uso pesado de paralelismo e concorrência onde é possível e viável. Mas… O que são essas coisas, afinal de contas?
Vamos falar sobre café.
A grande maioria dos programadores tem algo com café. De dez desenvolvedores que eu conheço, nove bebem café; o outro bebe alguma outra bebida com cafeína, como energéticos. Se você se encaixa no grupo dos que tomam café, muito provavelmente você sabe fazer o sua própria bebida. Então vamos elaborar alguns cenários a seguir.
Cenário A: Eu começo pegando um copo e colocando-o na pia. Encho-o com água e despejo a mesma dentro da minha cafeteira. Pego um filtro de papel, o coloco na cafeteira e jogo três colheres de café em pó nele. Ligo a cafeteira, espero o café coar e, depois, me sirvo despejando o líquido divino no copo. Então,bebo o café.
Cenário B: Após convidar e servir a minha irmã com um belo almoço em casa, pergunto se ela aceita um café. Ela gosta tanto quanto eu do néctar dos deuses, então aceita. A primeira coisa a fazer é encher o fervedor com água e colocá-lo sobre uma das bocas do fogão já acesas. A seguir, eu pego o meu coador, coloco e ajusto um filtro de papel nele e ponho pó de café. Cerca de quatro colheres. Enquanto a água começa a ferver, eu arrumo o que dá na mesa. Com a água fervida e o coador posicionado sobre uma jarra, despejo a água sobre o café lentamente em movimentos circulares, usando cada grão visível. Já é possível sentir o cheiro magnífico de café fresquinho. No que o líquido escoa para a jarra, pego dois copos. Em um deles coloco uma colher de açúcar. Eu prefiro puro, então não coloco no meu. O café termina de coar e eu o sirvo nos dois copos. Bebemos o café.
Cenário C: A hora da janta sempre conta com movimento intenso no restaurante. Eu cuido de fazer os espressos junto com colegas meus. Como bons apreciadores, sempre tentamos fazer o melhor café possível. Normalmente eu opero a máquina: carrego-a com os grãos e cuido para que sempre haja água fresca. Enquanto preparo duas xícaras, um dos meus colegas enche dois copinhos com água com gás e separa o doce extra que vai junto. Um terceiro colega coloca tudo em uma bandeja e sai em direção à mesa de nossos clientes. E assim entregamos mais um espresso enquanto chega outro pedido.
Ufa! Quanto café. Depois disso tudo, precisamos tomar cuidado para não desenvolver ou desencadear uma crise de gastrite. Atenção à quantidade de café que você toma. 🙂
Nos três cenários temos aplicações diferentes de como fazer café. O cenário A conta com execução sequencial, em que fazemos instrução a instrução, esperando cada uma delas terminar por completo antes de começar a próxima.
Já o cenário B conta com execução concorrente: não precisamos esperar o café terminar de coar para só então pegar os copos e servir. Podemos preparar o café enquanto a água ferve, e preparamos os copos enquanto o café termina de coar. Sabemos que cada uma dessas tarefas leva um tempo até que sejam concluídas, então agilizamos o processo preparando outras coisas em vez de esperar ociosamente, como é o caso do algoritmo sequencial do cenário A.
O cenário C, como você já deve ter previsto, é o que faz uso da execução paralela. O fato de termos pessoas diferentes fazendo tarefas diferentes ajuda e muito na performance do algoritmo. Claro que é um pouco mais difícil de gerenciar (e depurar) quando se trata de código, mas a ideia de que é mais eficiente já deve estar clara agora. Com um processador com múltiplos núcleos é possível dividir as tarefas em threads ou processos e juntar os pedaços do resultado no final.
Certo, e onde queremos chegar com tudo isso?
Algoritmos paralelos não são necessariamente novidade. Desde C já era possível criar threads e controlar (de certa forma) o fluxo por meio de mutexes. A novidade, no caso, é a concorrência: nos últimos anos, muitas linguagens de programação vêm adotando a concorrência de algumas formas. Algumas fazem uso de Promises ou Futures, estruturas para as quais passamos callbacks que são executados assincronamente; outras adotaram novas palavras-chave, como async
e await
para definir funções assíncronas e ordenar o programa que aguarde certas computações, respectivamente. Algumas adotaram ambas as formas. E há também a linguagem Go.
Já ouvi falar. Essa é a linguagem da Google, certo? Golang?
Essa mesma! A linguagem Go nasceu com concorrência em mente e possui uma forma muito facilitada de lidar com entrada e saída assíncrona. Programas concorrentes fazem uso de algo que chamamos de event loop. Esses event loops gerenciam qual pedaço de código deve ser executado em que instante. Go abstrai isso de forma que todos os programam rodam, por padrão, em um event loop. Todas as funções são assíncronas, e todas podem ser usadas de forma assíncrona ou não. Por exemplo, para somar dois números:
Essa é a forma como estamos acostumados a escrever código síncrono. Mas podemos chamar a função assincronamente colocando um simples go
à frente dela:
* Um chan
(channel) funciona como uma fila assíncrona e possibilita a passagem de mensagens entre as goroutines – as co-rotinas do Go.
Ainda que este exemplo seja simples, talvez seja possível ter uma ideia de o que é possível fazer com a linguagem. Com concorrência facilitada dessa forma, processamento assíncrono se torna algo comum e rotineiro no desenvolvimento. E essa é só uma das características legais e interessantes da linguagem! Nós falamos mais a fundo sobre essa e outras funcionalidades de Go no novo curso que lançaremos em breve de Desenvolvimento com Golang na 4Linux. Se você leu até aqui, é porque deve estar interessado. Então por que não conhecer um pouco mais do curso? Vem aprender Golang com a gente! 🙂
Líder em Treinamento e serviços de Consultoria, Suporte e Implantação para o mundo open source. Conheça nossas soluções:
About author
Você pode gostar também
Entenda os princípios S.O.L.I.D para melhorar a manutenção e escalabilidade do seu sistema
S.O.L.I.D. são 5 princípios da orientação a objetos que visam facilitar a manutenção e tornar seu sistema altamente escalável. Seu acrônimo define os diferentes princípios, sendo eles: SRP – Single
Desvendando o Zend Framework 3: O guia definitivo para desenvolvedores PHP
Se você está lendo este artigo provavelmente você já desenvolveu ou pretende desenvolver algum projeto de software. Talvez você nunca tenha usado um framework mesmo que não o Zend antes
Por que aprender Python pode impulsionar sua carreira em programação
Você que já automatiza suas rotinas com shell script precisa aprender Python. Dizem que se você quer trabalhar no Google o caminho mais fácil é aprender Python. Será que este