12 votes

Différence de performance entre les filtres et les fonctions de PowerShell

Je lis actuellement le livre Windows PowerShell 3.0 Step by Step pour mieux comprendre PowerShell.

À la page 201, l'auteur démontre qu'un filtre est plus rapide qu'une fonction ayant la même fonction.

Ce script prend 2,6 secondes sur son ordinateur :

MeasureAddOneFilter.ps1
Filter AddOne
{ 
 "add one filter"
  $_ + 1
}

Measure-Command { 1..50000 | addOne }

et celui-ci 4,6 secondes

MeasureAddOneFunction.ps1
Function AddOne
{  
  "Add One Function"
  While ($input.moveNext())
   {
     $input.current + 1
   }
}

Measure-Command { 1..50000 | addOne }

Si j'exécute ce code, j'obtiens exactement le contraire de son résultat :

.\MeasureAddOneFilter.ps1
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 226
Ticks             : 2266171
TotalDays         : 2,62288310185185E-06
TotalHours        : 6,29491944444444E-05
TotalMinutes      : 0,00377695166666667
TotalSeconds      : 0,2266171
TotalMilliseconds : 226,6171

.\MeasureAddOneFunction.ps1

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 93
Ticks             : 933649
TotalDays         : 1,08061226851852E-06
TotalHours        : 2,59346944444444E-05
TotalMinutes      : 0,00155608166666667
TotalSeconds      : 0,0933649
TotalMilliseconds : 93,3649

Quelqu'un peut-il m'expliquer cela ?

16voto

Ryan Ries Points 54671

À moins que l'auteur n'ait fourni des preuves supplémentaires, il est possible qu'il n'ait fait que raconter des histoires. Vous avez fait le test, obtenu le résultat et prouvé qu'il avait tort.

Edit : Extrait du blog de Jeffrey Snover :

Un filtre est une fonction qui ne possède qu'un bloc de script de processus.

Cela ne suffit pas à me convaincre qu'un filtre aura un avantage en termes de vitesse par rapport à une fonction, étant donné que les deux ont des blocs de processus identiques.

Par ailleurs, sur quel type d'équipement des années 1950 se trouve ce type qui met 4,6 secondes pour ajouter un chiffre à un autre ?

PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 7.7266

PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 0.4108

4,6 secondes, c'est énorme. Peut-être que l'auteur utilisait une sorte de version CTP de Powershell avant que les binaires ne soient modifiés. :P

Enfin, essayez votre test dans une nouvelle session Powershell, mais dans l'ordre inverse. Essayez d'abord la fonction et ensuite le filtre, ou vice versa :

PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 6.597    

PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 0.4055

Voir ? Le premier que vous courrez sera toujours plus lent. C'est simplement le fait d'avoir déjà chargé des éléments en mémoire qui rend la deuxième opération plus rapide, qu'il s'agisse d'une fonction ou d'un filtre.

J'admets cependant que la fonction semble toujours plus rapide que le filtre, quel que soit le nombre de fois où elle est exécutée.

Measure-Command { Function AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 13.9813

Measure-Command { Filter AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 69.5301

L'auteur avait donc tort... et maintenant je ne me sens plus coupable de n'avoir jamais utilisé un filtre au lieu d'une fonction.

8voto

p00ya Points 2513

En fait, la différence est beaucoup plus faible si l'on utilise le même $_ dans les deux tests. Je n'ai pas cherché la cause, mais je suppose que c'est parce que l'auteur n'utilise pas la même approche dans les deux tests. De plus, la sortie de la console peut interférer dans les résultats. Si l'on supprime ces parties, les résultats sont très similaires. Voir :

Function AddOneFunction
{  
    process {
        $_ + 1
    }
}

Filter AddOneFilter
{ 
    $_ + 1
}

write-host "First"
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds

write-host "Second"
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds

Les résultats seront très proches, même si vous changez l'ordre des commandes.

First

TotalMilliseconds
-----------------
        84.6742
        84.7646
        89.8603
        82.3399
        83.8195
Second
        86.8978
        87.4064
        89.304
        94.4334
        87.0135

La documentation indique également que les filtres sont essentiellement des raccourcis vers des fonctions ne comportant que le bloc de processus. Les fonctions, à moins d'être spécifiées avec un bloc de processus (ou une autre technique comme l'utilisation de variables automatiques telles que $input), s'exécutent une seule fois, n'utilisent pas d'entrée et ne passent pas à la commande suivante dans le pipeline.

Plus d'informations à l'adresse suivante https://technet.microsoft.com/en-us/library/hh847829.aspx y https://technet.microsoft.com/en-us/library/hh847781.aspx

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X