วิธีที่ดีกว่า (สะอาดกว่า) ในการละเว้นเอาต์พุตใน PowerShell คืออะไร? [ปิด]


139

สมมติว่าคุณมี method หรือ cmdlet ที่คืนค่าบางอย่าง แต่คุณไม่ต้องการใช้และไม่ต้องการส่งออก ฉันพบสองวิธีนี้:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

คุณใช้อะไร? แนวทางใดที่ดีกว่า / สะอาดกว่า ทำไม?

คำตอบ:


187

ฉันเพิ่งทดสอบสี่ตัวเลือกที่ฉันรู้

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

ดังนั้นฉันขอแนะนำให้คุณใช้อะไรก็ได้ แต่Out-Nullเนื่องจากค่าใช้จ่ายสูงเกินไป สิ่งที่สำคัญต่อไปสำหรับฉันคือความสามารถในการอ่าน ฉันชอบเปลี่ยนเส้นทาง$nullและตั้งค่าเท่ากับ$nullตัวเอง ฉันชอบแคสต์[Void]มากกว่า แต่อาจไม่เป็นที่เข้าใจเมื่อมองไปที่โค้ดหรือสำหรับผู้ใช้ใหม่

ฉันเดาว่าฉันชอบเปลี่ยนเส้นทางเอาต์พุตไปที่$nullไฟล์.

Do-Something > $null

แก้ไข

หลังจากความคิดเห็นของ stej อีกครั้งฉันตัดสินใจที่จะทำการทดสอบเพิ่มเติมกับไปป์ไลน์เพื่อแยกค่าใช้จ่ายในการทิ้งขยะที่ดีขึ้น

ต่อไปนี้คือการทดสอบบางส่วนด้วยท่อออบเจ็กต์ 1,000 รายการ

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

ในกรณีนี้Out-Nullมีค่าใช้จ่ายประมาณ 60% และ> $nullมีค่าโสหุ้ย 0.3%

ภาคผนวก 2017-10-16:เดิมทีฉันมองข้ามตัวเลือกอื่นด้วยOut-Nullการใช้-inputObjectพารามิเตอร์ การใช้สิ่งนี้ค่าใช้จ่ายดูเหมือนจะหายไป แต่ไวยากรณ์แตกต่างกัน:

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

และตอนนี้สำหรับการทดสอบบางอย่างด้วยท่อออบเจ็กต์ 100 รายการ

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

ที่นี่Out-Nullมีค่าใช้จ่ายประมาณ 60% อีกครั้ง ในขณะที่> $nullมีค่าใช้จ่ายประมาณ 4% ตัวเลขที่นี่แตกต่างกันเล็กน้อยจากการทดสอบไปสู่การทดสอบ (ฉันวิ่งแต่ละครั้งประมาณ 5 ครั้งและเลือกพื้นกลาง) Out-Nullแต่ผมคิดว่ามันแสดงให้เห็นเหตุผลที่ชัดเจนที่จะไม่ใช้


1
โดยปกติฉันจะใช้ VOID สำหรับสิ่งที่เป็นส่วนหนึ่งของบรรทัดภาษาและไม่เป็นโมฆะถ้ามันเป็นไปป์ไลน์ที่ยาวมากอยู่แล้ว
klumsy

27
Out-Nullอาจเป็นค่าใช้จ่าย แต่ .. ถ้าวางวัตถุชิ้นหนึ่งเป็นOut-Null0.076 มิลลิวินาที imho ก็ยังใช้ได้ดีสำหรับภาษาสคริปต์ :)
stej

1
ฉันยุ่งกับเรื่องนี้เล็กน้อยและฉันได้รับประสิทธิภาพที่ดีที่สุดเหนือ [void] และ> $ null โดยใช้ Out-Null -InputObject ($ (1..1000) |? {$ _ -is [int]})
tomohulk

1
จุดดีที่ดูเหมือนจะไม่มีค่าใช้จ่ายที่เห็นได้ชัดเจน
JasonMArcher

5
แม้ว่าจะเป็นการดีเสมอที่จะมีเกณฑ์มาตรฐานเพื่อเปรียบเทียบวิธีต่างๆในการทำบางสิ่งให้สำเร็จ แต่อย่ามองข้ามข้อสรุปอื่น ๆ ที่สามารถวาดได้ที่นี่: เว้นแต่คุณจะต้องทิ้งค่าหลายร้อยหลายพันครั้งที่ความแตกต่างของประสิทธิภาพมีน้อย และถ้าเสี้ยววินาทีที่นี่หรือที่นั่นมีความสำคัญกับคุณจริงๆคุณอาจไม่ควรใช้ PowerShell ตั้งแต่แรก โดยไม่ต้องตัดสินใด ๆ เกี่ยวกับการจัดอันดับของตัวเลือกในเรื่องเหล่านี้การเสียสละความเร็วเพื่อคุณภาพอื่น ๆ เช่นความสามารถในการอ่านและการแสดงเจตนาของโปรแกรมเมอร์ก็ไม่ใช่เรื่องแย่
BACON

28

ฉันรู้ว่านี่เป็นกระทู้เก่า แต่สำหรับผู้ที่รับคำตอบที่ได้รับการยอมรับของ @ JasonMArcher ข้างต้นในความเป็นจริงฉันแปลกใจที่พวกเราหลายคนไม่ได้รับการแก้ไขมานานหลายปีแล้วว่าจริง ๆ แล้ว PIPELINE เพิ่มความล่าช้าและไม่มีอะไรเกี่ยวข้องกับว่า มันเป็น Out-Null หรือไม่ ในความเป็นจริงถ้าคุณเรียกใช้การทดสอบด้านล่างคุณจะเห็นได้อย่างรวดเร็วว่าการร่าย "เร็วกว่า" เป็น [โมฆะ] และ $ void = เป็นเวลาหลายปีที่เราคิดว่ามันเร็วขึ้นนั้นเป็นเพียงแค่สโลว์และในความเป็นจริงช้ามากเมื่อ คุณเพิ่มการไปป์ไลน์ใด ๆ ก็ตาม กล่าวอีกนัยหนึ่งคือทันทีที่คุณไปยังสิ่งใดก็ตามกฎทั้งหมดของการไม่ใช้ค่าว่างเปล่าจะลงในถังขยะ

หลักฐานการทดสอบ 3 ครั้งล่าสุดในรายการด้านล่าง Out-null ที่น่าสยดสยองคือ 32339.3792 มิลลิวินาที แต่เดี๋ยวก่อน - แคสต์ไปยัง [โมฆะ] เร็วแค่ไหน? 34121.9251 มิลลิวินาที?!? WTF? นี่คือ # REAL ในระบบของฉันการแคสต์เป็น VOID นั้นช้าลงจริงๆ แล้ว = $ null ล่ะ? 34217.685ms ..... ยังคงเป็น friggin SLOWER! ดังที่การทดสอบอย่างง่ายสามครั้งล่าสุดแสดงให้เห็นว่า Out-Null นั้นเร็วกว่าในหลาย ๆ กรณีเมื่อมีการใช้งานไปป์ไลน์อยู่แล้ว

แล้วทำไมถึงเป็นเช่นนี้? เรียบง่าย มันเป็นภาพหลอน 100% เสมอที่การส่งไปยัง Out-Null ช้าลง อย่างไรก็ตามการ PIPING ไปยังสิ่งใด ๆ นั้นช้ากว่าและเราไม่รู้ด้วยเหตุผลพื้นฐานหรือไม่? เราอาจไม่รู้ว่าจะช้าลงแค่ไหน แต่การทดสอบเหล่านี้จะบอกเล่าเรื่องราวเกี่ยวกับค่าใช้จ่ายในการใช้ไปป์ไลน์หากคุณสามารถหลีกเลี่ยงได้ และเราไม่ได้ผิด 100% จริง ๆ เพราะมีสถานการณ์จริงจำนวนน้อยมากที่สิ่งที่ไม่เป็นโมฆะเป็นสิ่งชั่วร้าย เมื่อไหร่? เมื่อเพิ่ม Out-Null เป็นการเพิ่มกิจกรรมไปป์ไลน์เท่านั้น กล่าวอีกนัยหนึ่ง .... เหตุผลคำสั่งง่ายๆเช่น $ (1..1000) | Out-Null ตามที่แสดงด้านบนแสดงให้เห็นว่าเป็นจริง

หากคุณเพิ่มไปป์เพิ่มเติมใน Out-String ในทุกการทดสอบข้างต้น #s จะเปลี่ยนอย่างรุนแรง (หรือเพียงแค่วางรายการด้านล่าง) และอย่างที่คุณเห็นด้วยตัวคุณเอง Out-Null จะเร็วขึ้นในหลาย ๆ กรณี:

$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
+1 สำหรับจุดสำคัญนี้ ในความเป็นจริงไม่มีอะไรบังคับให้ใครใช้Out-Nullกับไปป์ไลน์เลยดังนั้นวิธีที่ดีที่สุดในการแสดงค่าใช้จ่ายของไปป์ไลน์คือการเรียกใช้Out-Nullและไม่มี ในระบบของฉันสำหรับการทำซ้ำ 10,000 ครั้งฉันจะได้รับ 0.576 วินาทีเป็นเวลาOut-Null -InputObject $GetProcessเทียบกับ 5.656 วินาที (ช้ากว่าเกือบ 10 เท่า) สำหรับ$GetProcess | Out-Null.
BACON

สวัสดี Collin ขอบคุณสำหรับคำตอบของคุณ ฉันเรียกใช้ตัวอย่างของคุณ แต่ในทุกชุด[void]และ$nullยังทำได้ดีกว่า| Out-Null. ฉันเข้าใจว่านี่เป็นเพราะไปป์ไลน์และเดลต้าหดตัวตามแบทช์ในภายหลัง แต่บนเครื่องของฉันOut-Nullไม่ทำงานเร็วกว่าในแบทช์ใด ๆ
Hinek

แต่แน่นอนว่าฉันต้องเห็นด้วยกับผู้ที่โต้แย้งว่าประสิทธิภาพนั้นไม่ใช่ทุกอย่างและความสามารถในการอ่านก็ควรเป็นปัจจัยด้วยเช่นกัน
Hinek

@Hinek ความคิดเห็นของคุณบ่งบอกว่าคุณพลาดประเด็นที่ Collin พูด ใช่[void]และ$nullจะทำงานได้ดีกว่า| Out-Null- เนื่องจากไฟล์|. ลองOut-Null -InputObject (expression)เปรียบเทียบ
Jonathan Gilbert

19

นอกจากนี้ยังมีOut-Nullcmdlet Add-Item | Out-Nullซึ่งคุณสามารถใช้ในท่อยกตัวอย่างเช่น

หน้าคู่มือสำหรับ 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".

คุณคิดอย่างไรเกี่ยวกับผลการทดสอบเกณฑ์มาตรฐานเล็กน้อยในคำตอบของ Jason
Hinek

น่าสนใจมากโดยเฉพาะความแตกต่างอย่างมากระหว่าง Out-Null กับวิธีอื่น ๆ ฉันคิดว่าจะเปลี่ยนไปใช้[void]แม้ว่าโซลูชัน Out-Null จะดูเป็น "powershellish" มากกว่าก็ตาม
Ocaso Protal

ฉันยังไม่แน่ใจว่าฉันชอบวิธีไหน แม้แต่ความแตกต่างที่ยิ่งใหญ่นี้ก็ดูเหมือนจะไม่สำคัญเท่าที่ stej แสดงความคิดเห็นไว้แล้ว
Hinek

2
@Hinek [void]ดูชัดเจนมาก (ไม่ใช่ powershellish อย่างที่บอก) คุณจะเห็นที่จุดเริ่มต้นของบรรทัดว่าไม่มีผลลัพธ์ในบรรทัดนี้ นี่เป็นข้อดีอีกอย่างและถ้าคุณทำ Out-Null ในวงใหญ่ประสิทธิภาพอาจเป็นปัญหาได้)
Ocaso Protal

11

ฉันจะพิจารณาใช้สิ่งต่างๆเช่น:

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

เอาต์พุตจาก$a.Addจะไม่ถูกส่งกลับ - ซึ่งถือไว้สำหรับ$a.Addการเรียกเมธอดทั้งหมด มิฉะนั้นคุณจะต้องใส่ไว้ข้าง[void]หน้าก่อนการโทรทุกครั้ง

ในกรณีง่ายๆฉันจะไปด้วย[void]$a.Addเพราะค่อนข้างชัดเจนว่าเอาต์พุตจะไม่ถูกใช้และถูกทิ้ง


3

ส่วนตัวผมใช้... | Out-Nullเพราะเป็นคนอื่น ๆ ได้เห็นรูปลักษณ์ที่เหมือนมากขึ้น "PowerShellish" วิธีการเมื่อเทียบกับและ ... > $null กำลังใช้ประโยชน์จากตัวแปรอัตโนมัติที่เฉพาะเจาะจงและสามารถมองข้ามได้ง่ายในขณะที่วิธีการอื่นทำให้เห็นได้ชัดด้วยไวยากรณ์เพิ่มเติมที่คุณตั้งใจจะละทิ้งผลลัพธ์ของนิพจน์ เพราะและในตอนท้ายของการแสดงออกฉันคิดว่าพวกเขาสื่อสารได้อย่างมีประสิทธิภาพ "นำทุกสิ่งที่เราทำมาจนถึงจุดนี้และทิ้งมันไป" และคุณสามารถแสดงความคิดเห็นได้ง่ายขึ้นสำหรับวัตถุประสงค์ในการดีบัก (เช่น) เมื่อเทียบกับการวางหรือก่อนนิพจน์เพื่อกำหนดสิ่งที่เกิดขึ้นหลังจากดำเนินการ[void] ...$null = ...... | Out-Null... > $null... # | Out-Null$null =[void]

ลองดูเกณฑ์มาตรฐานที่แตกต่างกัน: ไม่ใช่ระยะเวลาที่ใช้ในการดำเนินการแต่ละตัวเลือก แต่เป็นระยะเวลาที่ใช้ในการพิจารณาว่าแต่ละตัวเลือกทำอะไร เมื่อทำงานในสภาพแวดล้อมร่วมกับเพื่อนร่วมงานที่ไม่มีประสบการณ์กับ PowerShell หรือแม้แต่การเขียนสคริปต์เลยฉันมักจะพยายามเขียนสคริปต์ของฉันในลักษณะที่มีคนมาหลายปีต่อมาซึ่งอาจไม่เข้าใจภาษาที่พวกเขากำลังดูอยู่ก็สามารถมี โอกาสในการต่อสู้เพื่อค้นหาว่ากำลังทำอะไรอยู่เนื่องจากพวกเขาอาจอยู่ในสถานะที่ต้องสนับสนุนหรือแทนที่ สิ่งนี้ไม่เคยเกิดขึ้นกับฉันเป็นเหตุผลที่จะใช้วิธีการเดียวกับวิธีอื่น ๆ จนถึงตอนนี้ แต่ลองนึกดูว่าคุณอยู่ในตำแหน่งนั้นและคุณใช้helpคำสั่งหรือเครื่องมือค้นหาที่คุณชื่นชอบเพื่อพยายามค้นหาว่าOut-Nullทำ. คุณจะได้รับผลลัพธ์ที่เป็นประโยชน์ทันทีใช่ไหม? ตอนนี้พยายามที่จะทำเช่นเดียวกันกับและ[void] $null =ไม่ง่ายเลยใช่ไหม

จริงอยู่การระงับผลลัพธ์ของค่าเป็นรายละเอียดเล็กน้อยเมื่อเทียบกับการทำความเข้าใจตรรกะโดยรวมของสคริปต์และคุณทำได้แค่พยายาม "โง่" โค้ดของคุณให้มากก่อนที่คุณจะซื้อขายความสามารถในการเขียนโค้ดที่ดีสำหรับ a ความสามารถของมือใหม่ในการอ่าน ... โค้ดไม่ค่อยดี จุดของฉันคือเป็นไปได้ว่าบางคนที่มีความชำนาญใน PowerShell จะไม่ได้คุ้นเคยกับ[void], $null =ฯลฯ และเพียงเพราะเหล่านั้นอาจดำเนินการได้เร็วขึ้นหรือใช้การกดแป้นพิมพ์น้อยประเภทไม่ได้หมายความว่าพวกเขากำลังวิธีที่ดีที่สุดที่จะทำ สิ่งที่คุณกำลังพยายามทำและเพียงเพราะภาษาให้ไวยากรณ์ที่เล่นโวหารไม่ได้หมายความว่าคุณควรใช้มันแทนสิ่งที่ชัดเจนและเป็นที่รู้จักกันดี *

*ฉันกำลังพลที่มีความชัดเจนและที่รู้จักกันดีซึ่งผมไม่ทราบว่าจะเป็นOut-Null $trueตัวเลือกใดที่คุณรู้สึกว่าชัดเจนที่สุดและสามารถเข้าถึงได้มากที่สุดสำหรับผู้อ่านและผู้แก้ไขโค้ดของคุณในอนาคต (รวมด้วยตัวคุณเอง) ไม่ว่าจะพิมพ์เวลาหรือเวลาในการดำเนินการก็ตามนั่นคือตัวเลือกที่ฉันแนะนำให้คุณใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.