Що є кращим (чистішим) способом ігнорувати вихід у PowerShell? [зачинено]


134

Скажімо, у вас є метод або командлет, який щось повертає, але ви не хочете його використовувати, і ви не хочете виводити його. Я знайшов ці два способи:

Add-Item > $null

[void]Add-Item

Add-Item | Out-Null

Що ви використовуєте? Який кращий / чистіший підхід? Чому?


1
як-от версія [void] ... ще не була для мене, але я спробую її запам'ятати.
Массіф

Відповіді:


181

Я просто зробив кілька тестів із чотирьох варіантів, про які я знаю.

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 я знову вирішив зробити ще кілька тестів з трубопроводами, щоб краще ізолювати накладні витрати на вихід.

Ось кілька тестів з простим 1000 об'єктним конвеєром.

## 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 для речей, що входять до мовної лінії, і не має значення, якщо це вже великий довгий конвеєр
незграбний

25
Out-Nullможливо, накладні. Але .. якщо прошивка одного об’єкта до Out-Null0,076 мілісекунд, imho, це все ще чудово для сценарію мови :)
stej

1
Я трохи заплутався з цим, і я отримую найкращу ефективність за [void] і> $ null, використовуючи Out-Null -InputObject ($ (1..1000) |? {$ _ -Is [int]}).
tomohulk

1
Добре, що, схоже, немає помітних накладних витрат.
JasonMArcher

5
Хоча завжди добре мати еталони для порівняння різних способів досягнення чогось, давайте не будемо нехтувати іншим висновком, який можна зробити тут: якщо вам не доведеться відкидати значення в сотні тисяч разів, різниці в продуктивності незначні. І якщо мілісекунда тут чи там насправді має значення, ви, мабуть, не повинні використовувати PowerShell в першу чергу. Не приймаючи жодних суджень про те, як в цьому відносяться варіанти, не обов'язково погано жертвувати швидкістю для інших якостей, таких як читабельність та вираження намірів програміста.
БАКОН,

22

Я усвідомлюю, що це стара тема, але для тих, хто приймає відповідь @ JasonMArcher вище як факт, я дивуюсь, що вона не була виправлена ​​багатьма з нас протягом багатьох років, це насправді ПІДПРИЄМКА, що додає затримку і НІЧОГО не робити з тим це Out-Null чи ні. Насправді, якщо запустити тести нижче, ви швидко побачите, що той самий "швидший" кастинг до [void] і $ void = що роками ми всі використовували, думаючи, що це швидше, насправді ДОВІДЖЕ ТАКОЖ НЕБЕЗПЕЧНО, а насправді ДУЖЕ НЕЗАЛЕЖНО, коли ви додаєте БЕЗКОШТОВНІ трубопроводи. Іншими словами, як тільки ви підкажете що-небудь, все правило не використовувати out-null переходить у смітник.

Доказ, останні 3 тести у наведеному нижче списку. Жахливий Out-null становив 32339,3792 мілісекунди, але зачекайте - наскільки швидше було кастинг до [void]? 34121.9251 мс?!? WTF? Це РЕАЛЬНІ # в моїй системі, а передача на VOID була насправді ПОЛІШЕ. Як щодо = $ null? 34217.685ms ..... все ще friggin СЛІД! Отже, як показують три останні прості тести, Out-Null насправді швидше у багатьох випадках, коли трубопровід уже використовується.

Отже, чому це? Простий. Це і завжди було 100% галюцинацією, що передача каналу Out-Null проходила повільніше. Однак, ПІДПРИЄМСТВО ДО ЧОГО-то відбувається повільніше, і хіба ми цього не знали за допомогою базової логіки? Ми просто не можемо знати, ЯК СТОЛЬКО повільніше, але ці тести точно розповідають про вартість використання трубопроводу, якщо ви зможете його уникнути. І ми насправді не помилялися на 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 для внесення цього важливого моменту. Насправді, ніщо не змушує когось використовувати Out-Nullз трубопроводом, тому найкращий спосіб показати накладні трубопроводи - викликати Out-Nullз ним і без нього. У моїй системі за 10 000 ітерацій я отримую 0,576 секунди за Out-Null -InputObject $GetProcess5,656 секунди (майже в 10 разів повільніше) $GetProcess | Out-Null.
БАКОН

Привіт Коллін, дякую за вашу відповідь. Я пробіг ваші зразки, але у всіх партіях [void]і $nullвсе одно виступив краще, ніж | Out-Null. Я вважаю, що це відбувається через трубопровід, і дельта зменшується з пізнішими партіями, але на моїй машині Out-Nullне працює швидше в жодній з партій.
Хінек

Але, звичайно, я маю згоду з тими, хто стверджує, що продуктивність - це не все, і читальність також повинна визначатися.
Хінек

@Hinek Ваш коментар припускає, що ви пропустили точку сказання Колліна. Так, [void]і $nullвиступить краще, ніж | Out-Null- через |. Спробуйте Out-Null -InputObject (expression)для порівняння
Джонатан Гілберт

19

Є також Out-Nullкомандлет, який ви можете використовувати, наприклад, у конвеєрі 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".

Що ви думаєте про результати маленького тесту на еталон у відповіді Джейсона?
Хінек

Дуже цікаво, особливо дійсно величезна різниця між Out-Null та іншими методами. Я думаю, що [void]перейду до того, що рішення Out-Null виглядає більш "повноцінно".
Ocaso Protal

Я досі не впевнений, який мій вподобаний спосіб. Навіть ця величезна різниця здається навряд чи істотною, як stej вже коментував.
Хінек

2
@Hinek [void]виглядає дуже чітко (тож не повноцінно, як я вже сказав), ви побачите на початку рядка, що в цьому рядку немає виводу. Отже, це ще одна перевага, і якщо ви зробите 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тому що цілком зрозуміло, що вихід не буде використовуватися і відкидається.


2

Особисто я використовую, ... | Out-Nullтому що, як коментували інші, це виглядає як більш "PowerShellish" підхід порівняно з ... > $nullта [void] .... $null = ...використовує певну автоматичну змінну, і її можна легко не помітити, тоді як інші методи роблять очевидним додатковий синтаксис, що ви маєте намір відкинути вихід виразу. Тому що, ... | Out-Nullі ... > $nullна завершення висловлювання, я думаю, що вони ефективно спілкуються: "візьміть усе, що ми зробили до цього моменту, і викиньте його", плюс ви можете прокоментувати їх простіше для налагодження (наприклад ... # | Out-Null), порівняно з додаванням $null =чи [void] раніше вираз для визначення того, що відбувається після його виконання.

Давайте ж подивимось на інший орієнтир: не кількість часу, необхідного для виконання кожного варіанту, а кількість часу, яке потрібно для того, щоб з'ясувати, що робить кожен варіант . Працюючи в оточенні з колегами, які не мали досвіду PowerShell або взагалі навіть сценаріїв, я намагаюся писати свої сценарії таким чином, щоб хтось, який прийшов разом через роки, що може навіть не зрозуміти мову, на яку вони дивляться, може мати бойовий шанс розібратися, що це робить, оскільки вони, можливо, зможуть підтримати або замінити його. Мені це ніколи не спадало на думку використовувати один метод над іншими, але уявіть, що ви в такому положенні, і ви використовуєте helpкоманду чи улюблену пошукову систему, щоб спробувати дізнатися, щоOut-Nullробить. Ви отримуєте корисний результат негайно, правда? Тепер спробуйте зробити те ж саме з [void]і $null =. Не так просто, чи не так?

Зрозуміло, придушення виводу значення є досить незначною деталлю порівняно з розумінням загальної логіки сценарію, і ви можете лише спробувати "притупити" код так сильно, перш ніж торгувати своєю здатністю писати хороший код для здатність новачка читати ... не дуже хороший код. Суть в тому, що це можливо , що деякі , хто володіє PowerShell навіть не знайомі з [void], $null =і так далі, і тільки тому , що ті можуть виконуватися швидше або приймати менше натискань клавіш типу, не означає , що вони найкращий спосіб зробити те, що ви намагаєтеся зробити, і те, що мова дає вигадливий синтаксис, не означає, що ви повинні використовувати його замість чогось більш чіткого та відомого. *

* Я припускаю, що Out-Nullце ясно і добре відомо, яким я не знаю $true. Незалежно від того, який варіант ви вважаєте найяснішим та найдоступнішим для майбутніх читачів та редакторів свого коду (включно з вами), незалежно від типу введення чи часу на виконання, саме такий варіант я рекомендую використовувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.