Salut !
j'ai un générateur "gen" qui me génère des caractères (type str), je souhaite écrire ce qui est généré dans un fichier.
Je vois deux solutions évidentes pour ça :
# solution 1
for c in gen():
f.write(c)
# solution 2
out = ''.join(gen())
f.write(out)
(merci de ne pas tenir compte du nom des variables :p)
avantage de la solution 1 : si le générateur sort 1Go de données, on n'a pas besoin de tout charger en mémoire (c'est un peu le but du truc)
avantage de la solution 2 : c'est environ 5 fois plus rapide… (sur un test où le générateur sort 100ko de caractères)
Voyez-vous une alternative pas trop moche qui allie la vitesse de solution 2 avec une utilisation mémoire limitée ? (en python3)
Merci !
# Mémoire tampon
Posté par BFG . Évalué à 6.
Si votre générateur retourne un seul caractère à la fois, alors chaque caractère sera écrit, ce qui est lent. À l'inverse, la seconde méthode lit tous les caractères à la fois, comme si le générateur avait retourné tous les caractères à la fois, et écrit en une seule passe.
Vous pouvez avoir les avantages des deux méthodes en faisant une solution intermédiaire (entre "écrire 1 caractère" et "écrire tous les caractères") des 2 méthodes.
Vous pouvez modifier le générateur pour qu'il retourne plusieurs caractères à la fois, par exemple 2 caractères, ou 10, ou encore 4096 (n'hésitez pas à utiliser un bloc de plusieurs kilos, les systèmes de fichiers fonctionnent de toute manière par blocs, à plus forte raison sur les SSD).
Si vous ne pouvez pas modifier le générateur, vous pouvez quand même utiliser une variable "out" qui va accumuler 4096 caractères du générateur, et les écrire par paquets de 4096. Aussi, cette fonction pourra vous être utile.
# Bufferiser soi-même, ou laisser l'OS faire
Posté par benoar . Évalué à 3.
Je vois deux solutions :
1) Utiliser un StringIO, que tu remplies de X caractères, et que tu écris régulièrement dans ton fichier, genre
cf http://docs.python.org/3.0/library/io.html#io.BytesIO (je suppose que ce sera plutôt des bytes que des caractères que tu écriras)
C'est un peu équivalent à la solotion proposée par BFG.
2) Mapper le fichier en mémoire, et écrire directement les caractères dans ce tableau :
cf http://docs.python.org/3/library/mmap.html
[^] # Re: Bufferiser soi-même, ou laisser l'OS faire
Posté par BFG . Évalué à 4.
Attention, dans votre premier collage de code, vous écrivez 4096 fois le même caractère.
Voici à quoi ça aurait ressemblé avec
islice
:[^] # Re: Bufferiser soi-même, ou laisser l'OS faire
Posté par KAeL . Évalué à 1.
Les résultats sont grosso modo similaires à la solution "join unique".
(j'aime pas trop le lambda ici mais bon, avec partial dans ce cas ça aurait été moins clair)
merci
[^] # Re: Bufferiser soi-même, ou laisser l'OS faire
Posté par benoar . Évalué à 2.
Oups, faute d'inattention, merci. (et tu peux me tutoyer ;-))
Bon, comme je préfère sans join(), je propose un autre truc :
(bon, du coup une « simple » boucle sur i pourrait être plus lisible peut-être)
[^] # Re: Bufferiser soi-même, ou laisser l'OS faire
Posté par KAeL . Évalué à 1.
j'ai testé avec
et j'obtiens comme résultats (en secondes):
write direct 2.623428489023354
join du total 0.563591810001526
join par block 0.5687419429887086
StringIO 2.5268013479653746
le soucis de ta solution c'est qu'on fait un paquet d'appels à write (même si derrière y'a pas d'appel système à chaque fois)
[^] # Re: Bufferiser soi-même, ou laisser l'OS faire
Posté par benoar . Évalué à 2.
Moui, effectivement ; je ne pensais pas que ça donnerait de si mauvaise perfs…
Merci pour les résultats.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.