Question A propos d'un exemple

Plus d'informations
il y a 16 ans 2 mois #1711 par Laurent Dardenne
Salut,
j'ai une remarque concernant un script d'exemple en page 160 :
[code:1]# Convertion UnixDOS.ps1
param ($path=$( throw \"Chemin inexistant\"«»), $dest=$path)
$tab=get-content $path -encoding Byte
for ($i=0; $i -lt $tab.length; $i++)
{
if ($tab[$i] -eq 10)
{
$tab=$tab[0..$($i-1)] +[byte]13+$tab[$i..$tab.length]
$i++
}
}
$tab|Set-content $dest -encoding Byte[/code:1]
A la première lecture, didactiquement je n'ai rien à y redire mais coté performance on peut l'améliorer.
Comme vous le dites dans votre ouvrage il n'existe pas de méthode native permettant d'insérer une nouvelle valeur dans un tableau.

Le choix que vous avez fait convient très bien pour des fichiers de petite taille (< 20 Ko) au-delà cela commence à poser problème car chaque recopie du tableau est pénalisante en temps et en occupation mémoire.
En temps puisque qu'il peut y avoir + milliers de recopies qui à terme surchargeront le garbage collector de .NET.

J'ai réalisé qq tests avec un fichier de 5000 lignes d'une taille de 80.663 octets. En utilisant tous les compteurs de performance de .NET, nommés \"Mémoire CLR .NET\", on peut s'en rendre compte.
Le traitement prend à peu près 9 mn, l'occupation mémoire de PS passe de 27 Mo à 157 Mo et le temps processeur dans les 40-50%.
Pour l'occupation mémoire l'appel suivant remet les pendules à l'heure en fin de traitement :
[code:1][gc]::collect()[/code:1]
Pour le temps processeur cela me semble inhérent à PS.

Quant au temps de traitement, une autre approche peut être envisagée. On peut trés bien traiter le fichier via les classes .NET mais je me suis penché sur les fonctionnalités des fonctions de PowerShell. Ce qui fait que cette approche ne nécessite pas de connaissance particulière en .NET

Le principe est d'utiliser un pipeline entre Get-content et Set-content. On ne manipule plus un tableau d'octets mais un octet, enfin dans ce contexte un objet représentant un octet :
[code:1]
# Convertion UnixDOSV2.ps1
# Les caractères linefeed seul sont remplacés par linefeed+retour chariot

Function Convert{
Begin {
#Initialisation du pipeline avant la lecture du premier objet
$Trouve=$false;
$CR=13;
$LF=10;
}#Begin

Process {
#Traitement à proprement dit du pipeline
switch ($_) #Lecture de l'objet courant, un byte représentant un caractère ANSI
{
#L'objet courant est un caractère linefeed on mémorise sa présence. on passe à l'objet suivant...
10 {$Trouve=$true}
#L'objet courant est un autre caractère
default
{
#Le dernier objet lu était un caractère linefeed
if ($Trouve)
{
$Trouve=$false; # On réinitialise la variable de test pour l'objet suivant
[byte]$CR;[byte]$LF; # On écrit sur la sortie du pipeline CR+LF
if ($_ -ne $CR) {[byte]$_;} # Si l'objet courant n'est pas un retour chariot on l'écrit sur la sortie du pipeline
}
else {[byte]$_} #Le dernier objet lu était un caractère quelconque. Pas de modification
}#default
}#switch
} #process

End {
#Finalisation du traitement du pipeline
#Si le dernier objet lu était un caractère linefeed on le traite
if ($Trouve)
{[byte]$CR;[byte]$LF;} # On écrit sur la sortie du pipeline CR+LF
}#End
}[/code:1]
Usage :
[code:1]get-content FichierTest1.txt -encoding Byte|Convert|Set-content FichierTest2.txt -encoding Byte[/code:1]

Le temps de traitement est considérablement réduit et la mémoire est bien moins sollicitée.
A noter qu'on peut écrire plusieurs objets dans le pipeline dans une \"des méthodes prédéfinies\" de la fonction, qui on le voit ici peut être vue comme un \"passe-plat\" entre 2 cmdlets.

Voilà, c'était une petite critique qui se veut constructive.

Article sur le garbage collector
Tout ce que vous avez toujours voulu savoir sur les Ramasses-Miettes .NET
Détecter et éviter les fuites de mémoire et de ressources dans les applications .NET

[edit]
Bien évidemment l'usage de 2 disques physiques divise par 2 le temps de traitement :
[code:1]get-content C:\FichierTest1.txt -encoding Byte|Convert|Set-content D:\FichierTest2.txt -encoding Byte[/code:1]

Message édité par: Laurent Dardenne, à: 21/10/09 13:21<br><br>Message édité par: Laurent Dardenne, à: 24/06/10 14:34

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 16 ans 1 semaine #2114 par Arnaud Petitjean
Réponse de Arnaud Petitjean sur le sujet Re:A propos d'un exemple
Bonsoir BatchMan,

C'est une excellente remarque, en effet tu as parfaitement raison.
Ceci étant comme tu le soulignes, l'objectif visé était plus didactique qu'orienté performances.

Ton exemple illustre aussi le fait qu'il existe toujours pleins de façons différentes de résoudre un \&quot;problème\&quot;.

En tout cas merci pour cette remarque constructive ainsi que pour le lien fort intéressant sur le Garbage Collector; mécanisme relativement méconnu des admins systèmes de tous poils...

@++

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.073 secondes
Propulsé par Kunena