PowerShell'de çıktıyı yoksaymanın daha iyi (temiz) yolu nedir? [kapalı]


134

Diyelim ki bir şey döndüren bir yönteminiz veya cmdlet'iniz var, ancak kullanmak istemiyorsunuz ve çıktı almak istemiyorsunuz. Bu iki yolu buldum:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

Ne kullaniyorsun? Hangisi daha iyi / temiz yaklaşım? Neden?


1
[void] sürümü gibi ... henüz benim için değil, ama hatırlamaya çalışacağım.
Massif

Yanıtlar:


181

Bildiğim dört seçenekten bazı testler yaptım.

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

Bu yüzden Out-Null, genel gider nedeniyle bir şey kullanmanızı öneririm . Bir sonraki önemli şey, benim için okunabilirlik olacaktır. Kendime yönlendirme $nullve ona eşit ayarlama gibi $null. Ben döküm yapmayı tercih ederim[Void] , ancak koda veya yeni kullanıcılar için bu anlaşılır olmayabilir.

Çıkışı biraz yönlendirmeyi tercih ediyorum $null.

Do-Something > $null

Düzenle

Yine stej'in yorumundan sonra, çıktıyı çöpe atma yükünü daha iyi izole etmek için boru hatları ile biraz daha test yapmaya karar verdim.

Basit bir 1000 nesne boru hattı ile bazı testler.

## 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

Bu durumda, Out-Nullyaklaşık% 60'lık bir ek yüke ve > $nullyaklaşık% 0.3'lük bir ek yüke sahiptir.

Ek 2017-10-16: Başlangıçta parametre Out-Nullkullanımı ile başka bir seçeneği göz ardı ettim -inputObject. Bunu kullanarak ek yük kaybolur, ancak sözdizimi farklıdır:

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

Ve şimdi basit bir 100 nesne boru hattı ile bazı testler için.

## 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

Burada yine Out-Nullyaklaşık% 60 ek yük var. Süre > $nullyaklaşık% 4'lük bir ek yüke sahiptir. Buradaki sayılar testten teste biraz değişti (her birini yaklaşık 5 kez koştum ve ortadaki yeri seçtim). Ama bence kullanmamanın açık bir nedeni var Out-Null.


1
Ben tipik olarak bir dil satırının parçası olan şeyler için
VOID

25
Out-Nullbelki tepegözdür. Ama .. bir nesneyi Out-Null0.076 milisaniyeye pipetliyorsa, imho komut dosyası dili için hala mükemmel derecede iyi :)
stej

1
Bunu biraz karıştırıyorum ve Out-Null -InputObject ($ (1..1000) |? {$ _ -İs [int]}) kullanarak [void] ve> $ null üzerinde en iyi performansı elde ediyorum.
tomohulk

1
İyi bir nokta, gözle görülür bir ek yükü yok gibi görünüyor.
JasonMArcher

5
Bir şeyi başarmanın farklı yollarını karşılaştırmak için karşılaştırmalar yapmak her zaman iyi olsa da, burada çizilebilecek diğer sonuçları göz ardı etmeyelim: yüz binlerce kez performans farkları göz ardı edilebilir. Ve burada bir milisaniye gerçekten sizin için önemliyse, muhtemelen ilk etapta PowerShell kullanmamalısınız. Seçeneklerin bu açıdan nasıl sıralandığına dair herhangi bir yargılama yapmadan, okunabilirlik ve programcı niyeti ifade etmek gibi diğer nitelikler için hızı feda etmek her zaman kötü bir şey değildir.
BACON

22

Bunun eski bir iş parçacığı olduğunu anlıyorum, ancak @ JasonMArcher'ın yukarıdaki yanıtı kabul ettiği gerçeği için, birçoğumuzun yıllardır bildiği için düzeltilmediğine şaşırdım, aslında PIPELINE gecikme ekliyor ve Out-Null ya da değil. Aslında, aşağıdaki testleri çalıştırırsanız, aynı "daha hızlı" dökümün [void] ve $ void = olduğunu hepimiz daha hızlı düşünmeyi kullandığımızı göreceksiniz, aslında SADECE YAVAŞ ve aslında ÇOK YAVAŞ HERHANGİ BİR boru hattını eklersiniz. Başka bir deyişle, herhangi bir şeye yönelir inmez, null kullanmamanın tüm kuralı çöpe gider.

İspat, aşağıdaki listede son 3 test. Korkunç Out-null 32339.3792 milisaniyeydi, ama bekleyin - [void] 'e ne kadar hızlı döküm yapıyordunuz? 34121.9251 ms?!? O NE LAN? Bunlar sistemimdeki GERÇEK # ler, VOID'ye yayın yapmak aslında YAVAŞ. = $ Null ne dersin? 34217.685ms ..... hala çok zayıf! Bu nedenle, son üç basit testin gösterdiği gibi, Out-Null aslında boru hattının zaten kullanımda olduğu durumlarda HIZLI.

Peki, neden böyle? Basit. Out-Null'a giden boruların daha yavaş olduğu her zaman% 100 halüsinasyon olmuştur. Ancak, HER ŞEYE BORULMAK daha yavaştır ve bunu temel mantık yoluyla zaten bilmiyor muyduk? NE KADAR daha yavaş olduğunu bilmiyor olabiliriz, ancak bu testler, boru hattını kullanma olasılığından kaçınmanın maliyeti hakkında bir hikaye anlatacaktır. Ve biz gerçekten% 100 yanlış değildik çünkü dışarıda kötü olan çok küçük KÜÇÜK gerçek senaryo var. Ne zaman? Out-Null eklenirken SADECE boru hattı etkinliği eklenir. Başka bir deyişle .... $ (1..1000) gibi basit bir komutun nedeni | Yukarıda gösterilen Null dışı doğru gösterdi.

Yukarıdaki her teste Out-String'e basitçe ek bir boru eklerseniz #s kökten değişir (veya sadece aşağıdakileri yapıştırın) ve kendiniz de görebileceğiniz gibi, Out-Null aslında birçok durumda DAHA HIZLI olur:

$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

Bu önemli noktayı belirtmek için +1. Aslında, hiç kimseyi Out-Nullbir boru hattıyla kullanmaya zorlayan hiçbir şey yoktur , bu nedenle bir boru hattının ek yükünü göstermenin en iyi yolu, Out-Nullonunla ve onsuz çağırmaktır . Sistemimde 10.000 yineleme için Out-Null -InputObject $GetProcess5.656 saniyeye karşı 0.576 saniye (yaklaşık 10 kat daha yavaş) alıyorum $GetProcess | Out-Null.
BACON

Merhaba Collin, Cevabınız için teşekkürler. Numunelerinizi çalıştırdım, ancak tüm partilerde [void]ve $nullyine de daha iyisini yaptım | Out-Null. Bunun boru hattı nedeniyle olduğunu ve delta sonraki gruplar ile küçülüyor, ancak makinemde Out-Nullhiçbir partide daha hızlı performans göstermiyor.
Hinek

Ama elbette, performansın her şey olmadığını ve okunabilirliğin de hesaba katması gerektiğini savunanlar ile aynı fikirdeyim.
Hinek

@Hinek Yorumunuz Collin'in söylediği noktayı kaçırdığınızı gösteriyor. Evet, [void]ve $nulldaha iyi performans göstereceği | Out-Null- çünkü |. Out-Null -InputObject (expression)Karşılaştırma yapmayı deneyin .
Jonathan Gilbert

19

Out-NullBir boru hattında kullanabileceğiniz cmdlet de vardır, örneğin Add-Item | Out-Null.

Out-Null için manuel sayfa

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".

Jason'ın cevabındaki küçük kıyaslama testinin sonuçları hakkında ne düşünüyorsunuz?
Hinek

Çok ilginç, özellikle Out-Null ve diğer yöntemler arasındaki gerçekten büyük fark. Ben [void]Out-Null çözüm daha "powershellish" görünse bile geçeceğini düşünüyorum .
Ocaso Protal

Hala emin değilim, tercih ettiğim yol nedir. Bu büyük fark bile, stej'in zaten yorumladığı gibi pek önemli görünmüyor.
Hinek

2
@Hinek [void]çok net görünüyor (söylediğim gibi powershellish değil), çizginin başında bu çizgide çıktı olmadığını göreceksiniz. Yani bu başka bir avantajdır ve büyük döngüde bir Out-Null yaparsanız, performans bir sorun olabilir;)
Ocaso Protal

11

Gibi bir şey kullanmayı düşünürdüm:

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

Kaynağından çıktı $a.Adddöndürülmez - tüm $a.Addyöntem çağrıları için geçerlidir . Aksi takdirde, [void]her çağrıdan önce başa gelmeniz gerekir .

Basit durumlarda [void]$a.Add, çıktının kullanılmayacağı ve atılacağı oldukça açıktır.


2

Şahsen ben kullanıyorum, ... | Out-Nullçünkü diğerleri yorumladığı gibi, ... > $nullve ile karşılaştırıldığında daha "PowerShellish" yaklaşımına benziyor [void] .... $null = ...belirli bir otomatik değişkeni kullanıyor ve gözden kaçırılması kolay olabilirken, diğer yöntemler bir ifadenin çıktısını atmak istediğiniz ek sözdizimi ile bunu açıkça ortaya koyuyor. Çünkü ... | Out-Nullve ... > $nullifadenin sonuna gelip ben onlar etkili "Biz bu noktaya kadar yaptığım her şeyi alıp çöpe atın" artı (örneğin hata ayıklama amacıyla daha kolay onları yorum yapabilirsiniz iletişim düşünüyorum ... # | Out-Null), koyarak kıyasla $null =ya [void] daha önce ifadeyi yürüttükten sonra ne olacağını belirleme .

Yine de farklı bir karşılaştırmaya bakalım: her bir seçeneği yürütmek için gereken zaman değil, her bir seçeneğin ne yaptığını anlamak için geçen zaman . PowerShell konusunda deneyimli olmayan meslektaşları olan ortamlarda çalıştığım, hatta senaryo yazdım, senaryolarımı yıllar sonra gelen birinin baktığı dili bile anlayamayacak şekilde yazmaya çalışıyorum. bunu destekleme veya değiştirme durumunda olabilecekleri için ne yaptığını bulma şansı. Bu, şimdiye kadar bir yöntemi diğerlerinin üzerinde kullanmanın bir nedeni olarak hiç olmadı, ancak o konumda olduğunuzu ve helpne olduğunu bulmak için komutu veya favori arama motorunuzu kullandığınızı hayal edin.Out-Nullyapar. Hemen faydalı bir sonuç alırsınız, değil mi? Şimdi aynısını [void]ve ile yapmaya çalışın $null =. O kadar kolay değil, değil mi?

Kabul edilirse, bir değerin çıktısını bastırmak, bir komut dosyasının genel mantığını anlamaya kıyasla oldukça küçük bir ayrıntıdır ve bir kod için iyi kod yazma yeteneğinizle işlem yapmadan önce kodunuzu yalnızca "aptalca" yapmaya çalışabilirsiniz. aceminin okuma yeteneği ... çok iyi değil kodu. Benim noktası PowerShell akıcı kim bazılarıyla bile aşina olmayan mümkündür olduğunu [void], $null =bu hızlı yürütmek veya türüne az tuş vuruşlarını sürebilir sırf, vb, ve bunlar yapmanın en iyi yolu olduğu anlamına gelmez yapmaya çalıştığınız ve bir dilin size ilginç sözdizimi verdiği için, onu daha açık ve daha iyi bilinen bir şey yerine kullanmanız gerektiği anlamına gelmez. *

*Out-Null Açık ve iyi bildiğimi tahmin ediyorum ki , bilmiyorum $true. Hangi seçeneği seçerseniz seçin , yazma zamanı veya yürütme süresi ne olursa olsun, kodunuzun gelecekteki okuyucuları ve editörleri (kendiniz dahil) için en açık ve en erişilebilir olanıdır, kullanmanızı öneririm.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.