Para nós que cuidamos muitas vezes da infraestrutura dos servidores sabemos a importância de performance em nossos processos executados principalmente em produção, e esse cuidado se torna em vício real
É bem natural que qualquer pessoa que seja dessa parte de infraestrutura em geral seja viciado loucamente em performance e baixo consumo de hardware, por mais parruda que seja a aplicação sobrar nunca é demais
Treta
O shell é a coisa mais linda que temos nessa porra de vida, e como a nossa vida existem várias formas de fazer a mesma coisa, só que uma delas dificilmente dão o mesmo resultado na questão de performance, isso é claro né?!
E não diferentemente disso acontece com o echo, temos algumas alternativas como por exemplo a que chamamos de here-document (<<) usada no cat (para sair no STDOU) e também o printf que tem uma sintaxe bem parecida com a do echo e ainda também fiz com o printf com here-document direcionando a /dev/stdout.
E como qualquer viciado fiquei curioso em saber se eles se diferenciavam em performance nem que seja questão de milissegundos, e sei que você só está lendo esse artigo porque também é um viciado como eu 💀.
ANALISANDO
A forma que achei mais style fodastica foi usando o here-document do cat, mano cola só na sintaxe:
Mas deixei pra lá o meu style super hacker fodão e me liguei na performance, então obviamente ele foi o primeiro que eu teste, usando o strace pude mapear as requisições feitas ao executar aquele código e tive uma saída um pouco verbosa, mas estudaremos as saídas quando formos comparar os diferentes métodos.
Mas deixando de conversa mole vamos as paradas, primeiramente vamos aos testes.
Outra forma de testar foi usando o printf e apontando para escrever em /dev/stdout que é um link simbólico que aponta para outro link simbólico que aponta para outro, ele tem tantos links assim pelo simples motivo de identificar qual a TTY logada e coisas do tipo, o segundo link se localiza em /proc/self/fd/1 e o primeiro no meu caso estava dentro de /dev/pts/0.
AOS TESTES
Com minha duvida do caralho eu fiz um script afim de medir a porra dessa velocidade, e saber qual na prática era que iria executar mais rápido, e até que fim pude descobrir, meu teste foi simples, baseado em quatro funções onde elas exibiam 10000 vezes uma série de caracteres randômicos ("@#$%%&*I&FDFSRWEGsy€®³®ŧŋđðđðŋæ") e sem quebra de linhas ou espaços e nem tabs.
Na saída acima vemos que o echo foi mais rápido em questão de milessegundos, e o printf direcionando para o stdout foi o segundo mais veloz, com 0,102s, o printf ficou em terceiro lugar por 1 ms e o cat usando here-document ficou com a pior performance com 0,174s.
CAT (da morte)
O cat na prática e após ser executado cria um espaço dinâmico na memória para a alocação, e pra isso é necessário ela chamar também um descritor de arquivo fd (file descriptor) e saber o estado do arquivo, se existe ou se pode ou nao pode ser lido, conforme estão no padrão do módulo do libc unistd.h pode ser encontrado em /usr/include/unistd.h definindo: STDIN_FILENO, STDOUT_FILENO e STDERR_FILENO, que é respectivamente o número 1, 2 e 3.
Outra forma que colabora para que sua execução venha demorar mais é a função read(), para que ele imprima é necessário que tenham entrada de dados, e o cat não armazenou a entrada, a única que ele armazenou foi o primeiro argumento no qual foi ignorado por não ser um arquivo, e esse passo faz com que ela receba armazene em uma variável, e é aqui que a porca torce o rabo!
Se você executar strace cat, ele irá parar e esperar uma entrada em read(0, e após a entrada ele executa o script normalmente.
Esses passos fazem com que ele perca o tempo suficiente para que tenha uma maior demanda de tempo e aumenta o tempo de sua execução.
Printf VS Echo
Em nosso exemplo foi feito um teste de explosão de carácteres em cada função e foi analisada a performance, ok... Mas e se nós tentássemos criar um script que executaria cada função por várias vezes?
Como assim?
Se nós escrevermos um laço de repetição pra cada função de impressão na tela poderemos verificar qual o mais performático em uma perspectiva de varias vezes no código ser chamada a mesma função.