Accélérer l'écriture de fichiers
J'ai profilé certains legacy code que j'ai hérité avec cProfile. Il y avait un tas de modifications, j'ai déjà qui l'ont aidé (comme l'utilisation de simplejson C extensions!).
Fondamentalement, ce script est de l'exportation des données d'un système vers un fichier ASCII à largeur fixe de fichier. Chaque ligne est un enregistrement, et il a beaucoup de valeurs. Chaque ligne est 7158 caractères et contient une tonne d'espaces. Au total, le nombre d'enregistrement est de 1,5 millions d'enregistrements. Chaque ligne est généré à la fois, et prend un certain temps (5 à 10 lignes par seconde).
Que chaque ligne est généré, il est écrit sur le disque le plus simplement possible. Le profilage indique qu'environ 19-20% du temps total passé dans file.write()
. Pour un cas de test de 1 500 lignes que de 20 secondes. J'aimerais diminuer le nombre.
Maintenant, il semble que la prochaine victoire sera de réduire la quantité de temps passé à l'écriture sur le disque. Je tiens à le réduire, si possible. Je peux garder un cache d'enregistrements dans la mémoire, mais je ne peux pas attendre jusqu'à la fin et de vidage de tous à la fois.
fd = open(data_file, 'w')
for c, (recordid, values) in enumerate(generatevalues()):
row = prep_row(recordid, values)
fd.write(row)
if c % 117 == 0:
if limit > 0 and c >= limit:
break
sys.stdout.write('\r%s @ %s' % (str(c + 1).rjust(7), datetime.now()))
sys.stdout.flush()
Ma première pensée serait de garder un cache d'enregistrements dans une liste et de les écrire dans les lots. Serait-ce plus rapide? Quelque chose comme:
rows = []
for c, (recordid, values) in enumerate(generatevalues()):
rows.append(prep_row(recordid, values))
if c % 117 == 0:
fd.write('\n'.join(rows))
rows = []
Ma deuxième pensée serait d'utiliser un autre thread, mais qui me donne envie de mourir à l'intérieur.
- Quel est le goulot d'étranglement de la demande?
- Je croyais avoir été clair. Elle y consacre 20% de son temps à écrire sur le disque, une rangée à la fois.
- Ainsi, faire le changement et le profil il? C'est s'attendre à avoir peu d'effet, comme e/S de fichier est généralement en ligne de tampon... ou alors je l'assume.
- Le filetage ne va pas aider. Pourquoi êtes-vous rinçage tellement. Je veux dire, je sais que LeBron James "n'oublie jamais de chasse d'eau", mais avez-vous besoin de le faire à chaque fois que vous écrivez sur la sortie standard?
- le rinçage est pour sa sortie standard (stdout), pas le fichier en question.
- est droit. Je tire la chasse, juste pour le stdout de l'impression des rapports de situation. Cela n'arrive que tous les 117 lignes, ou environ une fois toutes les 20 secondes.
- Ce cas de test à partir de votre code: pastebin.com/pyC8puAZ, s'exécute en moins d'une seconde. Quelle que soit la cause de la lenteur, sa cause pas par ce que vous avez posté.
Vous devez vous connecter pour publier un commentaire.
En fait, votre problème n'est pas que
file.write()
de 20% de votre temps. Son que 80% du temps, vous n'êtes pas dansfile.write()
!D'écriture sur le disque est lent. Il n'y a vraiment rien que vous pouvez faire à ce sujet. Il suffit d'une très grande quantité de temps à écrire des trucs sur le disque. Il n'y a presque rien que vous pouvez faire pour l'accélérer.
Ce que vous voulez, c'est pour que les I/O de temps pour être la plus grande partie du programme de sorte que votre vitesse est limitée par la vitesse du disque dur pas votre temps de traitement. L'idéal est de
file.write()
d'avoir 100% d'utilisation!Le dosage de l'écrit dans des groupes de 500 a en effet d'accélérer les écritures de manière significative. Pour ce cas test de la rédaction de lignes individuellement pris 21.051 secondes en I/O, lors de l'écriture dans des lots de 117 pris 5.685 secondes pour écrire le même nombre de lignes. Lots de 500 a pris un total de seulement 0.266 secondes.
Vous pouvez faire mmap en python, qui pourrait de l'aide. Mais je soupçonne que vous avez fait une erreur alors que le profilage, parce que 7k * 1500 en 20 secondes environ 0,5 Mo/s. Faire un test dans lequel vous écrire des lignes au hasard avec la même longueur, et vous verrez, il est beaucoup plus rapide que cela.