Você sabe ler arquivos de texto grandes em PHP? Confira alguns códigos e o resultado obtido com eles.

Manipular arquivos é trivial para a maioria dos desenvolvedores mas acabamos nos acostumando com nossa zona de conforto e sempre repetindo códigos que já funcionaram algum dia. E isso pode não ser a melhor alternativa algumas vezes.

Pensando nisso, resolvemos avaliar vários códigos lendo um arquivo de textos (.csv) com tamanho acima de 1MB para termos uma ideia de como cada código reage em termos de memória, tempo e eficiência.

#1 Começando a idealizar

O primeiro arquivo de base para comparação é um script simples que muitos já devem ter esbarrado em algum dia em algum projeto e a lógica é simples: lê o arquivo, explode ele por linha \n e depois percorre o arquivo com foreach.

Simples assim, veja abaixo:

test01.php obteve os seguintes resultados:

0.01005 sec using 12.40 MB memory peak and 5102130 total strlen
0.00995 sec using 12.40 MB memory peak and 5102130 total strlen
0.00976 sec using 12.40 MB memory peak and 5102130 total strlen
0.01016 sec using 12.40 MB memory peak and 5102130 total strlen
0.00994 sec using 12.40 MB memory peak and 5102130 total strlen

#2 Usando file: a função pra ler e converter em array

Quem já viu um pouco mais da documentação do PHP já sabe que a função file() faz exatamente o que o script de cima se propõe e com isso economiza algumas linhas em nosso código. Basicamente, a mesma coisa, com menos linhas conforme abaixo:

test02.php obteve os seguintes resultados:

0.01011 sec using 12.43 MB memory peak and 5134576 total strlen
0.00994 sec using 12.43 MB memory peak and 5134576 total strlen
0.00990 sec using 12.43 MB memory peak and 5134576 total strlen
0.01052 sec using 12.43 MB memory peak and 5134576 total strlen
0.01040 sec using 12.43 MB memory peak and 5134576 total strlen

Dá pra dizer até que ficou um pouco mais lento mas usou o equivalente em memória. Bons observadores verão que há uma diferença no total do strlen mas isso é facilmente explicado: o arquivo .csv contém para cada linha um delimitador \n e a diferença está exatamente nesta quantidade.

#3 Usando array_map: a função para percorrer arrays ao invés do foreach

Certo, e agora? Alguns desenvolvedores já deixaram de usar foreach() para algumas demandas e passaram a usar funções de array para isso. Então, nosso terceiro e quarto caso agora serão com funções de array sendo array_map e array_walk.

0.00313 sec using 12.44 MB memory peak and 5134576 total strlen
0.00306 sec using 12.44 MB memory peak and 5134576 total strlen
0.00267 sec using 12.44 MB memory peak and 5134576 total strlen
0.00282 sec using 12.44 MB memory peak and 5134576 total strlen
0.00300 sec using 12.44 MB memory peak and 5134576 total strlen

3 VEZES MAIS RÁPIDO QUE FOREACH

Esse é o resultado obtido com array_map e com o array_walk (que deixei um código aqui também para teste) o resultado não chegou a ser mais rápido mas ficou próximo ao do array_map. A escolha entre usar o array_map ou array_walk ficaria a cargo da sua demanda contudo nos testes que executamos o array_map foi mais rápido neste cenário apresentado fosse com arquivos grandes ou não.

No entanto, até agora conseguimos velocidade ao percorrer o array mas não ganhamos nada em relação ao consumo de memória. // isso porque todas as funções usadas acima fazem a leitura do arquivo e trazem ela para memória.

#4 E se usarmos fopen: aquele das antigas

Ninguém disse que mais código era um problema, até porque tudo pode ser abstraído para facilitar.

Duas verdades:

  • Por muitas vezes o fopen não é usado por requerer mais linhas de desenvolvimento (escolha do desenvolvedor)
  • Arquivos que são grandes e que você não tem tanto controle assim e que precisam ser processados podem consumir MUITA MEMÓRIA e por isso uma solução que use menos memória pode ser MUITO IMPORTANTE.

Dito isto. todo mundo já usou funções fopen em algum momento de algum projeto. Quem é mais “antigo” deve até ter usado por falta de opção pois era o que tinha na época. Então vamos gastar um pouco mais de linha de código e fazer isso funcionar de outra forma:

0.00577 sec using 0.41 MB memory peak and 5134576 total strlen
0.00578 sec using 0.41 MB memory peak and 5134576 total strlen
0.00582 sec using 0.41 MB memory peak and 5134576 total strlen
0.00570 sec using 0.41 MB memory peak and 5134576 total strlen
0.00566 sec using 0.41 MB memory peak and 5134576 total strlen

30 VEZES MENOS MEMÓRIA

É… este é o resultado. Se comparado aos exemplos 1 e 2 o tempo de execução chegou a ser 40% a 50% ainda melhor.

Conclusão:

Os testes e estudos são importantes. E isso é o mais importante de tudo!!!

Outras conclusões:

  • Grandes arquivos podem requerer muita memória e fopen é eficaz quanto a isso.
  • Se você tem controle do tamanho do arquivo, precisa de velocidade e a memória a ser consumida não seja um problema no seu caso, array_map é gain!
  • array_map > foreach

Códigos disponíveis no Gist para estudo


DISCLAIMER:

O ambiente executado foi da minha própria máquina, nos exatos momentos que meu SO consumiam quantidade equivalente de recursos e etc. O exemplo escolheu um arquivo de tamanho considerável e poderia posteriormente ser comparado a arquivos menores e maiores. Por enquanto, é apenas um estudo de caso simples e legal para uma primeira ideia do que é possível se aprofundar. Outros scripts foram testados mas não tiveram impacto considerado relevantes para documentação no artigo, serão acrescidos ao gist para análise dos interessados.

11 Shares:
Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

You May Also Like
Leia Mais

Sejam bem-vindos Recrutas

Demos início hoje ao nosso Programa de Recrutas para times de tecnologia. Foram aproximadamente 100 inscrições que resultaram…
Leia Mais

2021 é o ano do PHP8

Para quem ainda não seu atualizou sobre as novidades do PHP8 estamos lançando uma playlist específica com exemplos.