Как стать автором
Обновить

PowerShell 3 – Finally on the DLR!

Время на прочтение 4 мин
Количество просмотров 4.1K
Автор оригинала: Joel 'Jaykul' Bennett
Для тех кто в танке сообщаем: PowerShell 3 будет официально выпущен вместе с Windows 8. CTP появился вместе с релизом Windows 8 Developer Preview (на конференции //Build/ от Microsoft в сентябре 2011). Второй CTP релиз появился аккурат под Рождество.
В течение нескольких месяцев я имел возможность поиграться с PowerShell 3 и теперь хочу рассказать Вам о своих впечатлениях.

Введение


С данным релизом много чего выпущено, но для меня (и меня — прим. перев.) главным изменением является то, что теперь PowerShell базируется на Dynamic Language Runtime, т.е. на среде, позволяющей внедрить динамические языки (напр., IronRuby, IronPython — прим. перев.) в Common Language Runtime (CLR), которая в свою очередь является ядром .NET Framework. DLR облегчает разработку динамических языков, запускаемых на .NET Framework. Конечно, PowerShell изначально был динамическим языком в .NET framework, но он появился раньше, поэтому исторически сложилось так, что он не был связан с DLR. И вот только теперь PowerShell был окончательно перенесен на DLR.
Несмотря на то, что PowerShell 3 реализован с использованием DLR, он не является динамическим языком во всех смыслах в сравнении с IronPython или IronRuby. Позвольте мне привести пару диаграмм из документации к DLR.

The DLR Overview



На диаграмме Вы можете увидеть три главные секции (в реализации DLR на CodePlex): hosting, runtime и language. Но как бы то ни было, не все из них портированы в .NET Framework 4.0 CLR.

Портированный DLR



* На диаграмме розовым выделено то, что перенесено в CLR 4.0 — прим. перев.
PowerShell 3 использует преимущества всего (или почти всего) того, что портировано в CLR, но в виду нежелания команда разработчиков не стала браться за портирование в операционную систему остальной части DLR. Таким образом, PowerShell 3 использует функционал DLR Language Implementation, вместе с Shared AST и деревьями Expression, а также DynamicObject и Call Site Caching рантайма, но не использует ничего из Common Hosting — ScriptRuntime, ScriptScope, ScriptSource или CompiledCode.
Это означает, что Вы не можете использовать API хостинга скриптов IronRuby и IronPython применительно к PowerShell. Но Вы можете использовать тот же API, что используется для хостинга PowerShell 2, только вместо PSObject нужно будет использовать Dynamic при обработке вывода в C#. И это на самом деле важная вещь.
Не хотелось бы рассматривать все изменения, с которыми вы столкнетесь в PowerShell 3 и которые явились прямым следствием перехода на DLR. Однако есть несколько серьезных вещей, на которые нужно обратить внимание. Во-первых, Вы можете заметить разницу в выполнении и производительности. То, что вы знали про соотношение производительности Скриптов, Функций и Коммандлетов, а также о времени загрузки скриптов и бинарников, кануло в лету с релизом PowerShell 3, т.к. теперь скрипты и функции больше не интерпретируются перед каждым вызовом, но компилируются, выполняются и даже кэшируются (время от времени). В результате первый запуск и первый импорт скрипта получается несколько более долгим, чем ожидается, но зато все последующие вызовы скриптов и функций из них выполняются значительно быстрее. И это касается всех скриптов в файлах и предопределенных функций в модулях. Последовательный запуск одной и тойже функции несколько раз теперь происходит намного быстрее, чем пастинг одного и тогоже кода несколько раз в консоль.
Еще одно значительное изменение — отказ от PSObject.
В PowerShell 3, PSObject является на самом деле объектом dynamic, и это означает что вывод коммандлетов и скриптов, вызванных из C#, может быть использован с ключевым словом «dynamic» вместо использования псевдо-reflection'овские методы, которые использовались с PSObject. К слову сказать, это только вершина айсберга.

В PowerShell 2 все в Extended Type System (ETS) базировалось на PSObject. Новые члены всегда добавлялись в PSObject, которым оборачивался «BaseObject» — неважно шли ли они из файла «types.ps1xml» или от вызова «Add-Member» на объекте. Если вызывался метод Add-Member на необернутом в PSObject объекте, то нужно было указывать параметр "-Passthru" и обрабатывать вывод, чтобы поиметь объект обернуты в PSObject, в который новый член может быть добавлен. К тому же, если объект кастовался к некоторому типу, добавленные ETS-члены в большинстве случаев терялись. Ниже пример скрипта:
$psObject = Get-ChildItem
$psObject.Count
$Count1 = ($psObject | where { $_.PSIsContainer }).Count

[IO.FileSystemInfo[]]$ioObject = Get-ChildItem
$ioObject.Count
$Count2 = ($ioObject | where { $_.PSIsContainer }).Count

$Count3 = ($ioObject | where { $_ -is [IO.DirectoryInfo] }).Count


В PowerShell 2 $Count1 и $Count3 будут содержать число папок в текущем каталоге, а $Count2 всегда будет иметь значение 0, т.к. свойство PSIsContainer на самом деле ETS-свойство, которое теряется при приведении к FileSystemInfo, из-за чего эта переменная всегда оценивается как ноль.
В PowerShell 3 же результат будет иным. Теперь PowerShell работает со всем как с dynamic-объектами, а Add-Member больше не нуждается в PSObject, чтобы отслеживать эти ETS-члены. Поэтому теперь скрипт, представленный выше, возвратит $Count1, $Count2 и $Count3 одинаковыми, как и ожидается. Очевидно, что опция "-Passthru" в Add-Member нужна лишь для того, чтобы тунелировать вещи, а не для простого присвоения. Но как бы то ни было, по-прежнему могут быть случаи, когда сущности все-таки стоит оборачивать в PSObject.
Думаю Вы согласитесь, что перенос PowerShell на DLR — это большой шаг вперед! Но будьте готовы к серьезным изменениям, способным поломать уже реализованный функционал. К примеру, попробуйте к скрипту выше добавить следующие три строки и выполнить их в PowerShell 2 и PowerShell 3 CTP2:
$Count1 -eq $Count2
$e = $ioObject[0] | Add-Member NoteProperty Note "This is a note" -Passthru
$f = $ioObject[0] | Add-Member NoteProperty Note "This is a note" -Passthru

В PowerShell 2 вы получите False, а две последующие строки отработают нормально. В PowerShell 3 первая строка вернет True, и в следствие того, что Add-Member модифицирует низлежащий объект даже необернутый в PSObject, третья строка породит ошибку «Add-Member: Cannot add a member with the name „Note“ because a member with that name already exists.»
В любом случае я уверен, что в будущем напишу еще что-нибудь о DLR и о том, какие изменения произошли в PowerShell с переходом на него. Но пока пищи для ума, думаю, будет достаточно.
Теги:
Хабы:
+26
Комментарии 54
Комментарии Комментарии 54

Публикации

Истории

Работа

.NET разработчик
66 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн