Questão Por que o Powershell é tão lento?


Eu tentei fazer uma coisa simples com o PowerShell, encontrar arquivos que ocupam mais espaço na unidade. eu usei ls + sort e ... demorou muito para mim.

Às vezes eu uso o gerenciador distante e comparado com o PowerShell, ele parece muito mais rápido e estável.

Ok, é baseado no .NET, mas o .NET não é tão lento. Eu espero ver algo leve e rápido! É o console!

Outra coisa, eu gostaria de ter algo parecido IEnumerable no PowerShell para ver os resultados imediatamente. É possível conseguir? Pode ajudar um pouco enquanto espero resultados, às vezes acho que é só sair.

EDITAR

Estou fazendo algo assim

ls -Recurse -ErrorAction SilentlyContinue | sort -Property Size | select -First 10

E acho que pode levar DAYS.

EDITAR

Apenas para comparar.

Código c # levou para mim cerca de 2 min. Com certeza não é ideal e não processou todos os arquivos, mas processou pelo menos> 95%.

void Main()
{
    GetFilesSize(@"C:\").OrderByDescending(x => x).Take(10).ToList();
}

public IEnumerable<long> GetFilesSize(string directory)
{
    var accessDenied = false;
    var dirList = new string[0]; 
    try
    {
        dirList = Directory.GetDirectories(directory);
    }
    catch{
        accessDenied = true;
    }

    if(accessDenied) yield break;

    foreach (var dir in dirList)
    {
        foreach (var size in GetFilesSize(dir))
        {
            yield return size;
        }
    }

    foreach (var fileName in Directory.GetFiles(directory))
    {
        if(fileName.Length>=260) continue;
        yield return new FileInfo(fileName).Length;
    }
}

4


origem


"Outra coisa ..." Não, por favor, não! Não faça uma segunda pergunta, que gerará respostas adicionais / diferentes / não relacionadas, na mesma pergunta. Basta criar uma nova pergunta sobre o SuperUser. - TOOGAM
Seria muito útil ver o seu código que é "tão lento" porque talvez não seja o PowerShell que é lento, e sim o seu código! - SimonS
Bem-vindo ao Superusuário! Por favor, tente fazer uma pergunta de cada vez (caso contrário, sua pergunta será encerrada como muito ampla). - DavidPostill♦
@Ramhound Se você ler meus comentários com cuidado, verá que eu me queixo sobre o desempenho do powershell, não sobre .net. O .NET é mencionado como base do powershell que funciona mais rápido. Não tenho certeza sobre a quantidade total de arquivos, estou tentando analisar a unidade inteira. Então eu acho que existem milhares de arquivos. - Neir0
@Ramhound eu calculei: 556458 - Neir0


Respostas:


O PowerShell é um programa escrito em .Net, mas utiliza interfaces para muitos intérpretes e tempos de execução diferentes quando está em execução. É um Shell, assim como o BASH, mesmo que esteja escrito em C, que não diz nada sobre os binários e scripts executados nele. Os executáveis ​​podem ser código .Net, comandos VDM / CMD, comandos shell do * nix, VB / C / WSScript, invocações do WMI, interfaces de API não gerenciadas, arquivos jar ou qualquer outra coisa. Essas opções afetam o desempenho do código em execução no shell, não o idioma em que o shell é escrito.

Agora, parece que você está tendo dificuldades com a implementação de um comando específico. Então a melhor pergunta é: por que ls lento para classificar quando chamado de dentro do PowerShell. Quando cavamos mais fundo, descobrimos que ls é um alias para 'Get-ChildItem', que retorna uma matriz de objetos contendo objetos System.IO.DirectoryInfo.

PS C:\Windows\system32> $x=Get-ChildItem ./
PS C:\Windows\system32> $x.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array 

PS C:\Windows\system32> $x[1].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DirectoryInfo                            System.IO.FileSystemInfo   

PS C:\Windows\system32>

Você pode recuperar o ls resultado, e depois canalizar isso em um Sort-Object  ligar e se comportará basicamente da mesma maneira que um IEnumerable faz.

Observe que IEnumerable não faz nada pelo desempenho. Você pode estar confundindo-o com o IQueryable, que define mas não executa uma consulta até o último segundo, presumivelmente depois de ter sido decorado com operações de filtragem e classificação, da maneira como o .Net faz via LinQ to Objects. Nesse caso, como Get-ChildItem não oferece um mecanismo de consulta otimizado ou fonte de dados indexada, você não pode comparar as operações modernas do banco de dados com as listagens de diretório.

Então, em última análise, tente algo como: ls ./ -recurse | Sort-Object Name -descending Para mim, segmentação System32, isso leva cerca de 20 segundos para processar e classificar 54430 arquivos.

Por fim, observe que você obtém um grande impacto no desempenho ao tentar enumerar um diretório ao qual não tem acesso pessoal, por isso, certifique-se de não recorrer a lugares para os quais não tem permissão de ir. + segundo espera para cada um.

Espero que ajude.


10



IEnumerable não fornece ganho de desempenho, mas permite ver os resultados imediatamente. Também no caso do PowerShell, ele pode melhorar muito o desempenho, por exemplo, se "ls" retornar IEnumerable, ele não carrega toda a árvore de arquivos na memória, o que pode ser uma grande sobrecarga. - Neir0
Eu tentei ls + tipo como você mencionou em seu post, eu quero verificar todos os arquivos na unidade, mas com certeza é impossível fazer ou eu acho que pode demorar alguns dias (realmente, porque eu deixei na noite e no na manhã não há nenhum resultado). Mas, por exemplo, se eu vou pegar utilwares especiais para verificar o espaço da unidade, eles funcionam muito rápido. Esse é meu argumento. Tudo, mover, copiar, pesquisar funciona lento no powershell e é irritante. - Neir0
tente redirecionar a saída para um arquivo. um disco de volume padrão não deve levar toda a noite para enumerar. você já está no limite de RAM ou o disco não é saudável? - Frank Thomas
Não tenho certeza, provavelmente algo de errado com a unidade, eu preciso fazer testes adicionais. Eu tenho outra ferramenta (TreeSize), que funciona muito rápido, por isso não é tão óbvio. - Neir0


O PowerShell foi criado para ser conveniente e não rápido. É uma troca - funciona nos bastidores, então o usuário precisa fazer menos. Fazer mais trabalho torna isso mais lento.

Veja que o seu código PowerShell é uma linha, para fazer mais do que o seu código C # faz em 15 linhas.

Ele faz mais - mesmo que você não esteja usando isso.

ls no Linux retorna strings, strings são simples e rápidas. Seu código .Net nem mantém o nome do arquivo, apenas mantém o tamanho, e os números são menores novamente Ainda mais rápido.

ls no PowerShell, retorna [FileInfo] e [DirectoryInfo] objetos - cada um tem que ser criado, e cada um tem que consultar o arquivo para preencher os outros campos como CreationTime e LastWriteTime e extensão e comprimento, e os campos de tempo para criar Objetos [DateTime].

Isso é muito mais lento para cada arquivo. Custos para permitir outras opções, mesmo quando você não as estiver usando - o código do PowerShell pode mudar para ter o tamanho dos primeiros 10 arquivos feitos em janeiro com uma alteração simples, sem outros cmdlets ou ferramentas, e ainda ser uma linha, o código C # teria que ser reescrito extensivamente, consultar o tempo de criação, levar o tempo de criação e tamanho para a classificação e assim por diante.

A razão pela qual você não vê os resultados imediatamente é porque você | sort. Isso torna isso impossível. E se você começou a produzir resultados imediatamente, mas o último arquivo encontrado precisa classificar para a frente? Então a saída estaria errada - IEnumerable não pode fazer nada sobre isso, | sort tem que reunir todas as entradas antes de poder produzir qualquer coisa. Seu tipo é mais rápido porque está classificando pequenas coisas

Seu código .Net pode fazer a classificação em si mais rapidamente porque está classificando um enumerável de [long], ele não precisa fazer nenhuma pesquisa de propriedade.

No geral, seu código faz muito menos, e fazer menos leva menos tempo. Mas você demorou mais para escrever e é menos flexível e mais focado. Uma troca.


2