Configurando ciência
Primeiro, alguns scripts nos ajudam a testar isso. Isso gera 2000 arquivos de script, cada um com uma única função pequena:
1..2000 | % { "Function Test$_('$someArg) { Return '$someArg * $_ }" > "test$_.ps1" }
Isso deve ser o suficiente para tornar a sobrecarga normal de inicialização não importa muito. Você pode adicionar mais, se quiser. Isso carrega todos eles usando dot-sourcing:
dir test*.ps1 | % {. $_.FullName}
Isso carrega todos lendo primeiro o conteúdo:
dir test*.ps1 | % {iex (gc $_.FullName -Raw)}
Agora, precisamos fazer uma inspeção séria de como o PowerShell funciona. Eu gosto de JetBrains dotPeek para um descompilador. Se você já tentou incorporar o PowerShell em um .NET aplicação , você verá que a montagem que inclui a maioria das coisas relevantes é System.Management.Automation
. Decompile aquele em um projeto e um PDB.
Para ver onde todo esse tempo misterioso está sendo gasto, usaremos um profiler. Eu gosto do criado no Visual Studio. É muito fácil de usar . Adicione a pasta que contém o PDB para os locais dos símbolos . Agora, podemos fazer uma execução de criação de perfil de uma instância do PowerShell que apenas executa um dos scripts de teste. (Defina os parâmetros da linha de comando para usar -File
com o caminho completo do primeiro script a ser testado. Defina o local de inicialização para a pasta que contém todos os minúsculos scripts.) Depois disso, abra as Propriedades no powershell.exe
entry sob Targets e altere os argumentos para usar o outro script. Em seguida, clique com o botão direito do mouse no item mais acima no Performance Explorer e escolha Iniciar criação de perfil . O profiler é executado novamente usando o outro script. Agora podemos comparar. Certifique-se de clicar em "Mostrar todos os códigos" se tiver a opção; para mim, que aparece em uma área de Notificações na visualização Resumo do Relatório de Criação de Perfil de Amostra.
Os resultados vêm em
Na minha máquina, a versão Get-Content
levou 9 segundos para percorrer os arquivos de script de 2000. As funções importantes no "Hot Path" foram:
Microsoft.PowerShell.Commands.GetContentCommand.ProcessRecord
Microsoft.PowerShell.Commands.InvokeExpressionCommand.ProcessRecord
Isso faz muito sentido: temos que esperar que Get-Content
leia o conteúdo do disco, e temos que esperar que Invoke-Expression
faça uso desses conteúdos.
Na versão de código-fonte, minha máquina gastou um pouco mais de 15 segundos para trabalhar nesses arquivos. Desta vez, as funções no Hot Path eram métodos nativos:
WinVerifyTrust
CodeAuthzFullyQualifyFilename
O segundo parece não estar documentado, mas WinVerifyTrust
"executa uma ação de verificação de confiança em um objeto especificado. " Isso é tão vago quanto possível, mas em outras palavras, essa função verifica a autenticidade de um determinado recurso usando um determinado provedor. Observe que não habilitei nenhum material sofisticado de segurança para o PowerShell e minha política de execução de scripts é Unrestricted
.
O que isso significa
Em suma, você está esperando que cada arquivo seja verificado de alguma forma, provavelmente verificado por uma assinatura, mesmo que isso não seja necessário quando você não restringir os scripts que podem ser executados. Quando você usa gc
e iex
do conteúdo, é como se tivesse digitado as funções no console, portanto, não há recursos para verificar.