Qual è il modo migliore (più pulito) per ignorare l'output in PowerShell? [chiuso]


134

Supponiamo che tu abbia un metodo o un cmdlet che restituisce qualcosa, ma non vuoi usarlo e non vuoi emetterlo. Ho trovato questi due modi:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

Cosa usi? Qual è l'approccio migliore / più pulito? Perché?


1
come la versione [nulla] ... non è stata ancora per me, ma proverò a ricordarla.
Massiccio

Risposte:


181

Ho appena fatto alcuni test delle quattro opzioni che conosco.

Measure-Command {$(1..1000) | Out-Null}

TotalMilliseconds : 76.211

Measure-Command {[Void]$(1..1000)}

TotalMilliseconds : 0.217

Measure-Command {$(1..1000) > $null}

TotalMilliseconds : 0.2478

Measure-Command {$null = $(1..1000)}

TotalMilliseconds : 0.2122

## Control, times vary from 0.21 to 0.24
Measure-Command {$(1..1000)}

TotalMilliseconds : 0.2141

Quindi suggerirei di utilizzare qualsiasi cosa tranne che Out-Nullper spese generali. La prossima cosa importante, per me, sarebbe la leggibilità. Mi piace in qualche modo reindirizzare $nulle impostare uguale a $nullme stesso. Preferisco trasmettere a [Void], ma potrebbe non essere così comprensibile quando guardo il codice o per i nuovi utenti.

Immagino di preferire leggermente il reindirizzamento dell'output a $null.

Do-Something > $null

modificare

Dopo il commento di Stej, ho deciso di fare altri test con tubazioni per isolare meglio il sovraccarico di cestinare l'output.

Ecco alcuni test con una semplice pipeline di 1000 oggetti.

## Control Pipeline
Measure-Command {$(1..1000) | ?{$_ -is [int]}}

TotalMilliseconds : 119.3823

## Out-Null
Measure-Command {$(1..1000) | ?{$_ -is [int]} | Out-Null}

TotalMilliseconds : 190.2193

## Redirect to $null
Measure-Command {$(1..1000) | ?{$_ -is [int]} > $null}

TotalMilliseconds : 119.7923

In questo caso, Out-Nullha un overhead di circa il 60% e un overhead di > $nullcirca lo 0,3%.

Addendum 16-10-2017: originariamente ho trascurato un'altra opzione Out-Null, l'uso del -inputObjectparametro. Usando questo il sovraccarico sembra scomparire, tuttavia la sintassi è diversa:

Out-Null -inputObject ($(1..1000) | ?{$_ -is [int]})

E ora per alcuni test con una semplice pipeline di 100 oggetti.

## Control Pipeline
Measure-Command {$(1..100) | ?{$_ -is [int]}}

TotalMilliseconds : 12.3566

## Out-Null
Measure-Command {$(1..100) | ?{$_ -is [int]} | Out-Null}

TotalMilliseconds : 19.7357

## Redirect to $null
Measure-Command {$(1..1000) | ?{$_ -is [int]} > $null}

TotalMilliseconds : 12.8527

Anche in questo caso Out-Nullha un overhead del 60% circa. Mentre > $nullha un sovraccarico di circa il 4%. I numeri qui variavano un po 'da test a test (ho eseguito ciascuno circa 5 volte e ho scelto la via di mezzo). Ma penso che mostri una chiara ragione per non usare Out-Null.


1
di solito uso VOID per le cose che fanno parte di una linea di linguaggio e sono nulle se è comunque già una lunga pipeline lunga
klumsy

25
Out-Nullè forse sovraccarico. Ma .. se si reindirizza un oggetto a Out-Null0,076 millisecondi, imho va ancora perfettamente bene per il linguaggio di scripting :)
stej

1
Stavo scherzando un po 'con questo e ottengo le migliori prestazioni su [void] e> $ null usando Out-Null -InputObject ($ (1..1000) |? {$ _ -Is [int]}).
Tomohulk,

1
Buon punto, sembra che non ci sia un notevole sovraccarico.
JasonMArcher,

5
Sebbene sia sempre utile disporre di parametri di riferimento per confrontare diversi modi di realizzare qualcosa, non trascuriamo l'altra conclusione che può essere tratta qui: a meno che non si debbano scartare valori centinaia di migliaia di volte le differenze di prestazioni sono trascurabili. E se un millisecondo qui o là conta davvero per te, probabilmente non dovresti usare PowerShell in primo luogo. Senza dare alcun giudizio sul modo in cui le opzioni si posizionano al riguardo, non è necessariamente una cosa negativa sacrificare la velocità per altre qualità come la leggibilità e l'espressione dell'intenzione del programmatore.
BACON,

22

Mi rendo conto che questo è un vecchio thread, ma per coloro che prendono la risposta accettata di @ JasonMArcher sopra come dato di fatto, sono sorpreso che non sia stato corretto molti di noi hanno saputo per anni che è in realtà la PIPELINE che aggiunge il ritardo e NIENTE da fare con se è Out-Null o no. Infatti, se esegui i test di seguito, vedrai rapidamente che lo stesso casting "più veloce" su [void] e $ void = che per anni abbiamo usato tutti pensando che fosse più veloce, sono in realtà SOLO COME LENTO e in effetti MOLTO LENTO quando aggiungi QUALSIASI pipelining di sorta. In altre parole, non appena si esegue il pipe su qualcosa, l'intera regola di non utilizzare out-null va nel cestino.

Prova, gli ultimi 3 test nell'elenco seguente. L'orribile Out-null era 32339.3792 millisecondi, ma aspetta: quanto più velocemente è stato lanciato su [void]? 34121.9251 ms?!? WTF? Questi sono REAL # sul mio sistema, il casting su VOID era in realtà PIÙ LENTO. Che ne dici di = $ null? 34217.685ms ..... ancora friggin SLOWER! Quindi, come mostrano gli ultimi tre semplici test, Out-Null è in realtà più veloce in molti casi quando la pipeline è già in uso.

Allora, perché? Semplice. È ed è sempre stata un'allucinazione al 100% che le connessioni a Out-Null fossero più lente. È comunque che PIPING TO ANYTHING è più lento e non lo sapevamo già attraverso la logica di base? Potremmo non sapere QUANTO più lentamente, ma questi test sicuramente raccontano una storia sul costo dell'utilizzo della pipeline se puoi evitarlo. E non ci sbagliavamo al 100% perché c'è un numero molto PICCOLO di scenari reali in cui il nulla è male. Quando? Quando si aggiunge Out-Null si aggiunge SOLO l'attività della pipeline. In altre parole .... il motivo è un semplice comando come $ (1..1000) | Out-Null come mostrato sopra ha mostrato vero.

Se aggiungi semplicemente una pipe aggiuntiva a Out-String ad ogni test sopra, i # cambiano radicalmente (o semplicemente incolla quelli qui sotto) e come puoi vedere tu stesso, l'Out-Null diventa in realtà più veloce in molti casi:

$GetProcess = Get-Process

# Batch 1 - Test 1 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$GetProcess | Out-Null 
} 
}).TotalMilliseconds

# Batch 1 - Test 2 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
[void]($GetProcess) 
} 
}).TotalMilliseconds

# Batch 1 - Test 3 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$null = $GetProcess 
} 
}).TotalMilliseconds

# Batch 2 - Test 1 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$GetProcess | Select-Object -Property ProcessName | Out-Null 
} 
}).TotalMilliseconds

# Batch 2 - Test 2 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
[void]($GetProcess | Select-Object -Property ProcessName ) 
} 
}).TotalMilliseconds

# Batch 2 - Test 3 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$null = $GetProcess | Select-Object -Property ProcessName 
} 
}).TotalMilliseconds

# Batch 3 - Test 1 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name | Out-Null 
} 
}).TotalMilliseconds

# Batch 3 - Test 2 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
[void]($GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name ) 
} 
}).TotalMilliseconds

# Batch 3 - Test 3 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$null = $GetProcess | Select-Object -Property Handles, NPM, PM, WS, VM, CPU, Id, SI, Name 
} 
}).TotalMilliseconds

# Batch 4 - Test 1 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$GetProcess | Out-String | Out-Null 
} 
}).TotalMilliseconds

# Batch 4 - Test 2 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
[void]($GetProcess | Out-String ) 
} 
}).TotalMilliseconds

# Batch 4 - Test 3 
(Measure-Command { 
for ($i = 1; $i -lt 99; $i++) 
{ 
$null = $GetProcess | Out-String 
} 
}).TotalMilliseconds

+1 per fare questo importante punto. In realtà, non c'è niente che costringa nessuno a usare Out-Nulluna pipeline, quindi il modo migliore per mostrare il sovraccarico di una pipeline è invocare Out-Nullcon e senza di essa. Sul mio sistema, per 10.000 iterazioni ottengo 0,576 secondi per Out-Null -InputObject $GetProcessvs. 5,656 secondi (quasi 10 volte più lento) per $GetProcess | Out-Null.
BACON,

Ciao Collin, grazie per la tua risposta. Ho eseguito i tuoi campioni, ma in tutti i lotti [void]e ho $nullcomunque eseguito un risultato migliore di | Out-Null. Capisco che questo è dovuto alla pipeline e il delta si restringe con i batch successivi, ma sulla mia macchina Out-Nullnon funziona più velocemente in nessuno dei batch.
Hinek,

Ma ovviamente devo essere d'accordo con coloro che sostengono che le prestazioni non sono tutto e che anche la leggibilità dovrebbe essere considerata.
Hinek,

@Hinek Il tuo commento suggerisce che ti sei perso il punto di quello che stava dicendo Collin. Sì, [void]e $nullfunzionerà meglio di | Out-Null- a causa del |. Prova Out-Null -InputObject (expression)per il confronto.
Jonathan Gilbert,

19

Esiste anche il Out-Nullcmdlet, che è possibile utilizzare in una pipeline, ad esempio Add-Item | Out-Null.

Pagina di manuale per Out-Null

NAME
    Out-Null

SYNOPSIS
    Deletes output instead of sending it to the console.


SYNTAX
    Out-Null [-inputObject <psobject>] [<CommonParameters>]


DETAILED DESCRIPTION
    The Out-Null cmdlet sends output to NULL, in effect, deleting it.


RELATED LINKS
    Out-Printer
    Out-Host
    Out-File
    Out-String
    Out-Default

REMARKS
     For more information, type: "get-help Out-Null -detailed".
     For technical information, type: "get-help Out-Null -full".

Cosa ne pensi dei risultati del piccolo test di riferimento nella risposta di Jason?
Hinek,

Molto interessante, in particolare l'enorme differenza tra Out-Null e gli altri metodi. Penso che [void]passerò a anche se la soluzione Out-Null sembra più "powershellish".
Ocaso Protal,

Non sono ancora sicuro di quale sia il mio modo preferito. Anche questa enorme differenza sembra poco significativa come già commentato stej.
Hinek,

2
@Hinek [void]sembra molto chiaro (anche se non powerhell come ho detto), vedrai all'inizio della riga che non c'è output in questa riga. Quindi questo è un altro vantaggio, e se si esegue un Out-Null in big loop, le prestazioni potrebbero essere un problema;)
Ocaso Protal

11

Vorrei prendere in considerazione l'utilizzo di qualcosa come:

function GetList
{
  . {
     $a = new-object Collections.ArrayList
     $a.Add(5)
     $a.Add('next 5')
  } | Out-Null
  $a
}
$x = GetList

L'output da $a.Addnon viene restituito, vale per tutte le $a.Addchiamate al metodo. Altrimenti dovrai anteporre [void]prima di ogni chiamata.

In casi semplici, vorrei andare [void]$a.Addperché è abbastanza chiaro che l'output non verrà utilizzato e verrà scartato.


2

Personalmente, lo uso ... | Out-Nullperché, come altri hanno commentato, sembra l'approccio più "PowerShellish" rispetto a ... > $nulle [void] .... $null = ...sta sfruttando una specifica variabile automatica e può essere facilmente trascurabile, mentre gli altri metodi rendono evidente con una sintassi aggiuntiva che si intende eliminare l'output di un'espressione. Perché ... | Out-Nulle ... > $nullalla fine dell'espressione penso che comunichino efficacemente "prendi tutto ciò che abbiamo fatto fino a questo punto e buttalo via", inoltre puoi commentarli più facilmente per scopi di debug (ad esempio ... # | Out-Null), rispetto a mettere $null =o [void] prima l'espressione per determinare cosa succede dopo averlo eseguito.

Diamo un'occhiata a un benchmark diverso, però: non la quantità di tempo necessaria per eseguire ciascuna opzione, ma la quantità di tempo necessaria per capire cosa fa ogni opzione . Avendo lavorato in ambienti con colleghi che non avevano esperienza con PowerShell o addirittura script, tendo a provare a scrivere i miei script in modo tale che qualcuno che arriva anni dopo che potrebbe anche non capire la lingua che stanno guardando può avere un combattere la possibilità di capire cosa sta facendo poiché potrebbero essere in grado di sostenerlo o sostituirlo. Questo non mi è mai venuto in mente come motivo per utilizzare un metodo rispetto agli altri fino ad ora, ma immagina di essere in quella posizione e usi il helpcomando o il tuo motore di ricerca preferito per provare a scoprire cosaOut-Nulllo fa. Ottieni immediatamente un risultato utile, giusto? Ora prova a fare lo stesso con [void]e $null =. Non è così facile, vero?

Certo, sopprimere l'output di un valore è un dettaglio piuttosto secondario rispetto alla comprensione della logica generale di uno script, e puoi solo provare a "smorzare" il tuo codice così tanto prima di scambiare la tua capacità di scrivere un buon codice per un capacità del principiante di leggere ... codice non così buono. Il mio punto è, è possibile che alcuni che hanno familiarità con PowerShell non abbiano nemmeno familiarità con [void], $null =ecc., E solo perché quelli possono essere eseguiti più velocemente o richiedere meno battiture per digitare, non significa che siano il modo migliore per fare cosa stai cercando di fare, e solo perché una lingua ti dà una sintassi bizzarra non significa che dovresti usarla al posto di qualcosa di più chiaro e meglio conosciuto. *

* Presumo che Out-Nullsia chiaro e noto, cosa che non so essere $true. Qualunque opzione tu ritenga più chiara e accessibile ai futuri lettori e redattori del tuo codice (incluso te stesso), indipendentemente dal time-to-type o dal tempo di esecuzione, questa è l'opzione che ti consiglio di utilizzare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.