Configurando a ciência
Primeiro, alguns scripts para nos ajudar 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 suficiente para fazer com que a sobrecarga normal da inicialização não importe muito. Você pode adicionar mais, se quiser. Isso carrega todos eles usando a fonte de pontos:
dir test*.ps1 | % {. $_.FullName}
Isso carrega todos eles, 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 do JetBrains dotPeek para um descompilador. Se você já tentou incorporar o PowerShell em um aplicativo .NET , verá que o assembly que inclui a maioria dos itens relevantes é System.Management.Automation
. Descompile esse em um projeto e um PDB.
Para ver onde todo esse tempo misterioso está sendo gasto, usaremos um criador de perfil. Eu gosto daquele incorporado ao Visual Studio. É muito fácil de usar . Adicione a pasta que contém o PDB aos locais dos símbolos . Agora, podemos executar uma 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 a serem usados -File
com o caminho completo do primeiro script a tentar. Defina o local de inicialização como a pasta que contém todos os pequenos scripts.) Depois que esse for feito, abra as Propriedades na powershell.exe
entrada em Destinos e altere os argumentos para usar o outro script. Em seguida, clique com o botão direito do mouse no item mais alto no Performance Explorer e escolha Iniciar criação de perfil. O criador de perfil é executado novamente usando o outro script. Agora podemos comparar. Certifique-se de clicar em "Mostrar todo o código" se for dada a opção; para mim, isso aparece em uma área de Notificações na exibição Resumo do Relatório de criação de perfil de amostra.
Os resultados vêm em
Na minha máquina, a Get-Content
versão 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 para Get-Content
ler o conteúdo do disco, e temos que esperar para Invoke-Expression
fazer uso desses conteúdos.
Na versão fonte de pontos, minha máquina passou um pouco mais de 15 segundos para trabalhar com esses 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 é o mais vago 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 recurso sofisticado de segurança para o PowerShell, e minha política de execução de scripts é Unrestricted
.
O que isso significa
Em resumo, você está aguardando a verificação de cada arquivo de alguma forma, provavelmente marcada por uma assinatura, mesmo que isso não seja necessário quando você não restringe os scripts que podem ser executados. Quando você gc
e iex
o conteúdo são como se você tivesse digitado as funções no console, não há recurso para verificar.