Je rappelle que les données sont sur une seule ligne dans le fichier data.xml. Comme le fichier est volumineux (4Go), je suis obligé de découper ce fichier en plusieurs fichiers pour pouvoir les parser sans saturer ma mémoire ram.
Pour ce faire je recherche une commande permettant de découper le fichier data.xml lorsqu’il trouve à chaque fois la 1000 ème balise fermante . Ainsi on a 1.xml (qui contient les 1000 premières balise ), 2.xml (qui contient les 1000 balises suivantes), 3.xml (qui contient les 1000 balises suivantes), et ainsi de suite.
Une idée ?
C’est vrai que j’aurais pu utiliser sed -i “s/></>\n</g” data.xml | split -d -l 1000, mais comme ma mémoire ram est limité, la partie sed de cette commande est aborté au bout d’un certain temps.
my $buff1;
my $buff2 = ‹ ›;
my $index = 1;
my $count = 0;
open OUT, ‹ > ›, $index.‹ .xml ›;
while(read FILE, $buff1, $size) {
chomp $buff1;
$buff2 .= $buff1;
while($buff2 =~ /(.?</fichier>)(.)/g) {
++$count;
if($count gt $limit) {
++$index;
close OUT;
open OUT, ‹ > ›, $index.‹ .xml › or die « $! »;
}
say OUT $1;
$buff2 = $2;
}
}
say OUT $buff2;
close OUT;
close FILE;[/code]
Niveau perf ça doit pas être terrible parce qu’on utilise une lecture simple et pas un mmap, mais la consommation mémoire devrait rester correcte (voir très correcte). Faudrait aussi regarder si sed n’a pas une option pour refaire le comportement que j’ai écris en sed./
Merci misterFreeze, j’ai essayé ton script, mais ça ne me coupe pas à toutes les 1000 , mais ça coupe à chaque , comme si le paramètre my $limit = 1000 a été zappé durant l’exécution du script.
Je n’ai jamais fait de perl dans ma vie (même si en voyant ton code, ça a l’air un language simpliste, mais de bonne réputation pour les regex).
[quote=“MisterFreez”]Code:
sed -l4096 ‘s@()@\1\n@g’ fichier.xml | split -dl1[/quote]
=> ça ne marche pas car ma mémoire ram n’est pas assez suffisante pour aller jusqu’au bout.
Je laisse tomber sed, car j’ai l’impression que sed charge d’abord tout le fichier avant le parsage.
Pour le script perl corrigé, toujours le même résultat (pas de découpage à toutes les 1000 ), mais ce que j’aime bien dans ton script, il lit progressivement le fichier (comme le parsage événementiel d’un fichier xml).
bonjour,
avec 8GB de swap cela devrait passer, il y a un pb a condition de travailler sous root (SHMMAX)
et là cela swap!!!
une autre solution plus élègante et en rapport avec l’architecture,
on considère que le fichier d’une ligne passe dans un tuyau
sur ce tuyau on ouvre une fenétre (taille buffer)
on parcoure chaque caractère à la recherche de l’élèment indiquant une fin de phrase
donc écrit la phrase, on rajoute \n dans ce fichier sortie
résumons:
-un fichier en entrée
un fichier en sortie
une fenètre de travail
pour le fun on compte le nombre d’insertion (nombre de ligne)
on inscrit également l’heure de début et de fin de traitement
[quote=« fluo »][quote=« MisterFreez »]Code:
sed -l4096 ‹ s@()@\1\n@g › fichier.xml | split -dl1[/quote]
=> ça ne marche pas car ma mémoire ram n’est pas assez suffisante pour aller jusqu’au bout.
Je laisse tomber sed, car j’ai l’impression que sed charge d’abord tout le fichier avant le parsage.[/quote]
Ça me déçoit de sa part…
Hum, je suis perplexe. Voici un version qui me donnera peut être plus d’infos :
[code]#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
my $filename = shift;
open FILE, ‹ < ›, $filename or die « $! »;
my $size = 4096;
my $limit = 1000;
my $buff1;
my $buff2 = ‹ ›;
my $index = 1;
my $count = 0;
open OUT, ‹ > ›, $index.‹ .xml ›;
while(read FILE, $buff1, $size) {
chomp $buff1;
$buff2 .= $buff1;
while($buff2 =~ /(.?</fichier>)(.)/g) {
++$count;
if($count gt $limit) {
die « count = $count ; limit = $limit ; index = $index »;
$count = 0;
++$index;
close OUT;
open OUT, ‹ > ›, $index.‹ .xml › or die « $! »;
}
say OUT $1;
$buff2 = $2;
}
}
say OUT $buff2;
close OUT;
close FILE;[/code]
[quote=« jb1 »]on considère que le fichier d’une ligne passe dans un tuyau
sur ce tuyau on ouvre une fenétre (taille buffer)
on parcoure chaque caractère à la recherche de l’élément indiquant une fin de phrase
donc écrit la phrase, on rajoute \n dans ce fichier sortie[/quote]
Tu vois une grande différence avec ce que fais mon script perl ?
[ul]
[li]Lire le fichier petit à petit dans un buffer[/li]
[li]découper selon le motif et écrire dans un fichier[/li]
[li]changer de fichier dès qu’on passe une certaine limite[/li][/ul]
Pourquoi ça ? Éventuellement si tu cherche à utiliser des pipes ou mmap ça peut se comprendre mais c’est dispo dans les autres langages aussi.
Merci misterFreeze, ça marche, ça consomme très peu de mémoire.
Mais d’après toi, qui est le plus rapide (je voudrais un classement du plus rapide vers le moins rapide) pour le parsage de gros fichier avec regex en ligne de commande ? : bash, php, perl, python ?
Probablement perl, les autres sont tous au même niveau quant au traitement des expressions régulières, ils utilisent PCRE qui est écrite en C.
La performance intrinsèque des langage (et leur gestion des chaines de caractère par exemple) jour probablement un rôle pus déterminant. perl a simplement l’avantage d’avoir des expressions régulières extrêmement poussées (cf. : articles.mongueurs.net/magazines … ag106.html). Une expression régulière ça s’optimise.
En l’occurrence dans le cas présent je présume que le traitement a du être très long. C’est la lecture du fichier qui cause principalement ce problème. J’ai choisi d’avoir un buffer de 4096 caractères en ayant dans l’idée que c’était de l’ASCII et ainsi lire toujours l’équivalent d’un buffer noyau (une page mémoire soit 4096o), mais c’est loin d’être optimal. Ce qu’il faudrait c’est utiliser Mmap et utiliser une taille de buffer qui correspond à la taille moyenne du contenu de la balise comme ça :
[ul]
[li]tu laisse le noyau faire ça tambouille pour mapper le fichier en mémoire de manière optimisé[/li]
[li]tu limite le nombre de tour de boucle qui contient l’expression régulière[/li][/ul]
Note : je suis pas un expert des expressions régulières, mais je pense qu’il est possible d’optimiser celle que j’ai donné pour supprimer la boucle. Ce serais probablement plus propre et peut être plus rapide.
bonsoir MisterFreez et les autres,
mon problème, je ne parle pas « Perl » mais d’autres langages
bref:
pour la mémoire si 8GB de barrettes la valeur de shmmax est à revoir
A+
JB1