Cách tốt hơn (sạch hơn) để bỏ qua đầu ra trong PowerShell là gì? [đóng cửa]


134

Giả sử bạn có một phương thức hoặc một lệnh ghép ngắn trả về một cái gì đó, nhưng bạn không muốn sử dụng nó và bạn không muốn xuất nó. Tôi tìm thấy hai cách sau:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

Bạn dùng gì? Đó là cách tiếp cận tốt hơn / sạch hơn? Tại sao?


1
như phiên bản [void] ... chưa dành cho tôi, nhưng tôi sẽ cố nhớ nó.
Thánh lễ

Câu trả lời:


181

Tôi vừa làm một số thử nghiệm trong bốn lựa chọn mà tôi biết.

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

Vì vậy, tôi sẽ đề nghị bạn sử dụng bất cứ điều gì nhưng Out-Nulldo chi phí hoạt động. Điều quan trọng tiếp theo, với tôi, sẽ là khả năng đọc. Tôi giống như chuyển hướng đến $nullvà thiết lập bằng $nullchính mình. Tôi sử dụng để thích truyền vào [Void], nhưng điều đó có thể không dễ hiểu khi liếc vào mã hoặc cho người dùng mới.

Tôi đoán tôi hơi thích chuyển hướng đầu ra $null.

Do-Something > $null

Biên tập

Sau khi nhận xét của stej một lần nữa, tôi quyết định thực hiện thêm một số thử nghiệm với các đường ống để cách ly tốt hơn chi phí đầu ra.

Dưới đây là một số thử nghiệm với 1000 đường ống đối tượng đơn giản.

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

Trong trường hợp này, Out-Nullcó khoảng 60% chi phí và > $nullcó khoảng 0,3% chi phí.

Phụ lục 2017-10-16: Ban đầu tôi bỏ qua một tùy chọn khác với Out-Null, việc sử dụng -inputObjecttham số. Sử dụng điều này, chi phí dường như biến mất, tuy nhiên cú pháp thì khác:

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

Và bây giờ cho một số thử nghiệm với một đường ống 100 đối tượng đơn giản.

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

Ở đây một lần nữa Out-Nullcó khoảng 60% chi phí. Trong khi > $nullcó một chi phí khoảng 4%. Các con số ở đây thay đổi một chút từ kiểm tra đến kiểm tra (tôi chạy mỗi lần khoảng 5 lần và chọn điểm giữa). Nhưng tôi nghĩ rằng nó cho thấy một lý do rõ ràng để không sử dụng Out-Null.


1
tôi thường sử dụng VOID cho những thứ là một phần của dòng ngôn ngữ và không có giá trị nếu nó đã là một đường ống dài lớn dù sao đi nữa
klumsy

25
Out-Nullcó thể là trên đầu. Nhưng .. nếu chuyển một đối tượng thành Out-Null0,076 mili giây, imho vẫn hoàn toàn ổn đối với ngôn ngữ kịch bản :)
stej

1
Tôi đã gặp rắc rối với điều này một chút và tôi có được hiệu suất tốt nhất qua [void] và> $ null bằng cách sử dụng Out-Null -InputObject ($ (1..1000) |? {$ _ -Is [int]}).
tomohulk

1
Điểm tốt, dường như không có chi phí đáng chú ý.
JasonMArcher

5
Mặc dù luôn có điểm chuẩn để so sánh các cách khác nhau để hoàn thành một cái gì đó, nhưng đừng bỏ qua kết luận khác có thể được rút ra ở đây: trừ khi bạn phải loại bỏ các giá trị hàng trăm nghìn lần sự khác biệt về hiệu suất là không đáng kể. Và nếu một phần nghìn giây ở đây hoặc thực sự có vấn đề với bạn, có lẽ bạn không nên sử dụng PowerShell ở nơi đầu tiên. Không đưa ra bất kỳ phán xét nào về cách các tùy chọn xếp hạng trong các vấn đề này, không nhất thiết phải hy sinh tốc độ cho các phẩm chất khác như khả năng đọc và thể hiện ý định lập trình viên.
BACON

22

Tôi nhận ra đây là một chủ đề cũ, nhưng đối với những người tham gia câu trả lời được chấp nhận của @ JasonMArer'ser là sự thật, tôi ngạc nhiên rằng nó đã không được sửa chữa trong nhiều năm qua, đó thực sự là PIPELINE thêm sự chậm trễ và KHÔNG làm gì với việc liệu nó là Out-Null hay không. Trên thực tế, nếu bạn chạy các bài kiểm tra bên dưới, bạn sẽ nhanh chóng thấy rằng việc truyền "nhanh hơn" tương tự thành [void] và $ void = rằng trong nhiều năm qua, tất cả chúng ta đều nghĩ rằng nó nhanh hơn, thực sự CHỈ CÒN R SL RÀNG và thực tế RẤT RẤT bạn thêm BẤT K pip đường ống nào. Nói cách khác, ngay khi bạn chuyển sang bất cứ điều gì, toàn bộ quy tắc không sử dụng out-null sẽ đi vào thùng rác.

Bằng chứng, 3 bài kiểm tra cuối cùng trong danh sách dưới đây. Out-null khủng khiếp là 32339.3792 mili giây, nhưng chờ đã - tốc độ được truyền tới [void] nhanh hơn bao nhiêu? 34121.9251 ms?!? WTF? Đây là những # THỰC trên hệ thống của tôi, chuyển sang VOID thực sự là SLOWER. Làm thế nào về = $ null? 34217.685ms ..... vẫn còn SLOWER SLOWER! Vì vậy, như ba thử nghiệm đơn giản cuối cùng cho thấy, Out-Null thực sự NHANH CHÓNG trong nhiều trường hợp khi đường ống đã được sử dụng.

Vì vậy, tại sao điều này? Đơn giản. Đó là và luôn luôn là ảo giác 100% rằng đường ống đến Out-Null chậm hơn. Tuy nhiên, việc PIPING TO ANYINGING chậm hơn và chúng ta đã không biết điều đó thông qua logic cơ bản? Chúng tôi có thể không biết NHIỀU chậm hơn, nhưng những thử nghiệm này chắc chắn sẽ kể một câu chuyện về chi phí sử dụng đường ống nếu bạn có thể tránh được. Và, chúng tôi đã không thực sự sai 100% bởi vì có một số lượng rất nhỏ các kịch bản thực sự trong đó out-null là xấu xa. Khi nào? Khi thêm Out-Null là thêm hoạt động đường ống CHỈ. Nói cách khác .... lý do một lệnh đơn giản như $ (1..1000) | Out-Null như hình trên cho thấy sự thật.

Nếu bạn chỉ cần thêm một ống bổ sung vào Out-String cho mọi thử nghiệm ở trên, thì #s thay đổi hoàn toàn (hoặc chỉ dán những cái bên dưới) và như bạn có thể thấy, Out-Null thực sự trở thành FASTER trong nhiều trường hợp:

$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 để thực hiện điểm quan trọng này. Trên thực tế, không có gì buộc bất cứ ai sử dụng Out-Nullvới một đường ống cả, vì vậy cách tốt nhất để thể hiện chi phí hoạt động của đường ống là gọi Out-Nullvà không có nó. Trên hệ thống của tôi, trong 10.000 lần lặp, tôi nhận được 0,576 giây Out-Null -InputObject $GetProcessso với 5,656 giây (chậm hơn gần 10 lần) $GetProcess | Out-Null.
BACON

Xin chào Collin, cảm ơn câu trả lời của bạn. Tôi đã chạy mẫu của bạn, nhưng trong tất cả các đợt [void]$nullvẫn thực hiện tốt hơn | Out-Null. Tôi hiểu rằng điều này là do đường ống và đồng bằng co lại với các đợt sau, nhưng trên máy của tôi Out-Nullkhông hoạt động nhanh hơn trong bất kỳ lô nào.
Hinek

Nhưng tất nhiên tôi phải đồng ý với những người tranh luận rằng hiệu suất không phải là tất cả và khả năng đọc cũng là yếu tố.
Hinek

@Hinek Nhận xét của bạn cho thấy bạn đã bỏ lỡ quan điểm của những gì Collin đang nói. Có, [void]$nullsẽ thực hiện tốt hơn | Out-Null- bởi vì |. Hãy thử Out-Null -InputObject (expression)so sánh.
Jonathan Gilbert

19

Ngoài ra còn có Out-Nulllệnh ghép ngắn, mà bạn có thể sử dụng trong một đường ống, ví dụ , Add-Item | Out-Null.

Trang hướng dẫn sử dụng 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".

Bạn nghĩ gì về kết quả của bài kiểm tra điểm chuẩn nhỏ trong câu trả lời của Jason?
Hinek

Rất thú vị, đặc biệt là sự khác biệt rất lớn giữa Out-Null và các phương pháp khác. Tôi nghĩ rằng tôi sẽ chuyển sang [void]mặc dù giải pháp Out-Null có vẻ "quyền hạn" hơn.
Ocaso Protal

Tôi vẫn không chắc chắn, cách ưa thích của tôi là gì. Ngay cả sự khác biệt lớn này dường như hầu như không đáng kể như stej đã nhận xét.
Hinek

2
@Hinek [void]trông rất rõ ràng (tho không mạnh mẽ như tôi đã nói), bạn sẽ thấy ở đầu dòng không có đầu ra trong dòng này. Vì vậy, đây là một lợi thế khác và nếu bạn thực hiện Out-Null trong vòng lặp lớn, hiệu suất có thể là một vấn đề;)
Ocaso Protal

11

Tôi sẽ xem xét sử dụng một cái gì đó như:

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

Đầu ra từ $a.Addkhông được trả về - giữ cho tất cả các $a.Addcuộc gọi phương thức. Nếu không, bạn sẽ cần phải trả trước [void]trước mỗi cuộc gọi.

Trong các trường hợp đơn giản, tôi sẽ sử dụng [void]$a.Addvì khá rõ ràng rằng đầu ra sẽ không được sử dụng và bị loại bỏ.


2

Cá nhân, tôi sử dụng ... | Out-Nullbởi vì, như những người khác đã nhận xét, có vẻ như cách tiếp cận "PowerShellish" hơn so với ... > $null[void] .... $null = ...đang khai thác một biến tự động cụ thể và có thể dễ dàng bỏ qua, trong khi các phương thức khác làm cho nó rõ ràng với cú pháp bổ sung mà bạn dự định loại bỏ đầu ra của một biểu thức. Bởi vì ... | Out-Null... > $nullđến cuối của biểu thức tôi nghĩ rằng họ giao tiếp hiệu quả "lấy mọi thứ chúng tôi đã làm cho đến thời điểm này và vứt nó đi", ngoài ra bạn có thể nhận xét chúng dễ dàng hơn cho mục đích gỡ lỗi (ví dụ ... # | Out-Null), so với đặt $null =hoặc [void] trước biểu thức để xác định những gì xảy ra sau khi thực hiện nó.

Tuy nhiên, hãy xem xét một điểm chuẩn khác nhau: không phải là lượng thời gian cần thiết để thực hiện từng tùy chọn, mà là lượng thời gian cần thiết để tìm ra mỗi tùy chọn làm gì . Đã từng làm việc trong môi trường với các đồng nghiệp chưa có kinh nghiệm với PowerShell hoặc thậm chí là viết kịch bản, tôi có xu hướng cố gắng viết các kịch bản của mình theo cách mà một người nào đó đến sau nhiều năm mà thậm chí không hiểu ngôn ngữ họ đang nhìn có thể có cơ hội chiến đấu để tìm ra những gì nó đang làm vì họ có thể phải ở trong một vị trí phải hỗ trợ hoặc thay thế nó. Điều này chưa bao giờ xảy ra với tôi như một lý do để sử dụng một phương pháp so với các phương pháp khác cho đến bây giờ, nhưng hãy tưởng tượng bạn đang ở vị trí đó và bạn sử dụng helplệnh hoặc công cụ tìm kiếm yêu thích của bạn để cố gắng tìm hiểu điều gìOut-Nulllàm. Bạn nhận được một kết quả hữu ích ngay lập tức, phải không? Bây giờ hãy cố gắng làm tương tự với [void]$null =. Không dễ như vậy phải không?

Được cấp, triệt tiêu đầu ra của một giá trị là một chi tiết khá nhỏ so với việc hiểu logic tổng thể của tập lệnh và bạn chỉ có thể cố gắng "hạ thấp" mã của mình thật nhiều trước khi bạn giao dịch khả năng viết mã tốt cho người mới có khả năng đọc ... mã không tốt. Quan điểm của tôi là, nó có thể là một số người thông thạo PowerShell thậm chí không quen thuộc với [void], $null =, vv, và chỉ vì những người có thể thực hiện nhanh hơn hoặc mất tổ hợp phím ít hơn để loại, không có nghĩa là họ là những cách tốt nhất để làm những gì bạn đang cố gắng thực hiện và chỉ vì một ngôn ngữ mang lại cho bạn cú pháp kỳ quặc không có nghĩa là bạn nên sử dụng nó thay vì một thứ gì đó rõ ràng hơn và được biết đến nhiều hơn. *

* Tôi cho rằng đó Out-Nulllà rõ ràng và nổi tiếng, mà tôi không biết là $true. Bất kỳ tùy chọn nào bạn cảm thấy rõ ràng và dễ tiếp cận nhất đối với người đọc và người chỉnh sửa mã trong tương lai (bao gồm cả bản thân bạn), bất kể thời gian thực hiện hay thời gian thực hiện, đó là tùy chọn tôi khuyên bạn nên sử dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.