Lectura de fitxers molt grans amb Generator (yield)
Els algorismes que hem vist fins ara carreguen tot el fitxer a la memòria. Això pot ser lent i ineficient quan són grans, i més en servidors d'aplicacions web.
Per això, podem utilitzar un Generator, que el que fa és anar llegint el fitxer línia per línia.
A continuació, per provar com funciona un Generador i comprovar que aquesta hipotesi és certa (que amb Genrator i yield estalviem temps i recursos), desenvoluparem un benchmark per comparar els dos enfocaments utilitzant un fitxer de 10,000 línies i 12 columnes.
import numpy as np
import time
# Funció per llegir tot el fitxer a la memòria
def read_file_all_at_once(file_path):
with open(file_path, 'r') as file:
lines = file.readlines()
processed_lines = [line.strip() for line in lines]
return processed_lines
# Funció per llegir el fitxer línia per línia amb generador
def read_file_with_generator(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
# Generar fitxer de prova
num_lines = 12000
num_columns = 50
data = np.random.rand(num_lines, num_columns)
file_path = 'large_file.txt'
with open(file_path, 'w') as file:
for row in data:
file.write(','.join(map(str, row)) + '\n')
# Benchmarking sense generadors
start_time = time.time()
all_lines = read_file_all_at_once(file_path)
end_time = time.time()
print("Temps de lectura sense generadors:", end_time - start_time)
# Benchmarking amb generadors
start_time = time.time()
for line in read_file_with_generator(file_path):
pass # Processa cada línia aquí
end_time = time.time()
print("Temps de lectura amb generadors:", end_time - start_time)
Resultats del Benchmarking:
Temps de lectura sense generadors: 0.05058765411376953
Temps de lectura amb generadors: 0.017226219177246094
Com veiem, el temps de lectura amb generadors és inferior, per tant és més eficient a nivell de temps.
Com es crea el Generador ?
La gràcia de la funció read_file_with_generator
és que en comptes de tenir el return
té la paraula clau yield
.
La paraula clau yield és la clau que converteix aquesta funció en un generador. En lloc de retornar un valor i sortir de la funció (com faria return), yield retorna una línia processada (sense espais en blanc al principi i al final) i suspèn l'execució de la funció. La propera vegada que es cridi next()
sobre l'iterador retornat per aquesta funció, la execució es reprèn just després del yield.
Referències consultades:
- https://www.udacity.com/blog/2021/09/getting-started-with-try-except-in-python.html
- https://realpython.com/python-download-file-from-url/
- https://www.udacity.com/blog/2021/09/getting-started-with-try-except-in-python.html
Referències pendents d'incloure per ampliar:
- https://medium.com/@technige/what-does-requests-offer-over-urllib3-in-2022-e6a38d9273d9
- https://stackabuse.com/bytes/how-to-unzip-a-gz-file-using-python/
- https://bito.ai/resources/unzip-gz-file-python-python-explained/ . https://pywombat.com/articles/shutil-python
Relatives a AsyncIO: