TL; DR Eu tenho uma quantidade tão grande de pacotes que está prejudicando meu tempo de inicialização. Se você não acredita que possa ser esse o caso, continue lendo.
O tempo de inicialização do meu Emacs é bem pequeno. Eu não uso use-package
, apenas ajustei toneladas de ganchos autoload
es para que quase todo o código seja adiado. Na realidade, a coisa toda é carregada em menos de meio segundo, apesar de parecer uma bagunça louca.
No entanto, com o tempo, notei que meu tempo de inicialização fica minuciosamente mais lento, inexplicavelmente. Eventualmente, chegou ao ponto em que o tempo de inicialização é ≥ 1 segundo. Eu finalmente tive o suficiente e descobri a raiz do problema. Finalmente, comentei meu ~/.emacs
arquivo inteiro e descobri que o tempo de inicialização ainda era ≥ 1 segundo. Na verdade, ele só tinha raspado ~ 0.2
segundos, às vezes até menos. Então eu tentei emacs -q
e descobri que o tempo de inicialização era ~ 0.1
segundos.
Ao examinar esta seção do manual Elisp, descobri por que emacs -q
estava reduzindo tanto o tempo de inicialização. Aparentemente, o emacs -q
Emacs impede três ações na inicialização:
- carregando seu arquivo init
- carregando seu
default.el
arquivo - chamando
package-initialize
Já descartamos meu arquivo init, pois comentar todo o processo ~/.emacs
não faz quase nada. Eu não uso um default.el
arquivo, então isso também é descartado. O que deixa package-initialize
como o culpado pelo desempenho atingido.
Por que package-initialize
consumir tanto tempo de inicialização? Essa foi a primeira pergunta que me fiz. Não estou carregando automaticamente tudo? Bem, sim. Mas esse é precisamente o problema.
Eu encontrei este post que explica que "ativar" pacotes consiste em ler arquivos de carregamento automático e definir caminhos de carregamento. Obviamente, isso implica em uma penalidade de E / S quando você possui muitos pacotes, porque possui muitos arquivos de carregamento automático para ler e muitos caminhos para definir. Infelizmente, sem isso, a tarefa de gerenciar carregamentos automáticos fica nas mãos do usuário. Em outras palavras, sem deixar package.el
rastrear o sistema de arquivos para carregar arquivos e caminhos automaticamente, eu mesmo precisaria gerenciar isso, o que poderia ser um processo tedioso e propenso a erros.
Eu preferiria não seguir esse caminho. Atualmente, tenho 116 pacotes, dos quais 107 do ELPA e 25 dos quais são dependências. Estou certo de que esse número enorme é o que está degradando tanto meu desempenho. Mas estou com um dilema porque não quero remover nenhum dos meus pacotes.
Existe algum remédio em tal situação para recuperar meu tempo de inicialização do raio?
Atualizar:
Iniciamos um novo tópico na emacs-devel
lista de discussão sobre alguns patches de Stefan Monnier (uma descrição desses patches está aqui ) para resolver esse problema. Qualquer pessoa é bem-vinda para testar seus patches e dar feedback.
Outra atualização:
Parece que Stefan Monnier não está mais interessado nesta questão ou não está recebendo minhas mensagens. Estou inclinado a acreditar no primeiro, o que é bom, embora eu apreciasse algum tipo de resposta dele, se esse for o caso. De qualquer forma, o código que ele produziu para esse problema até agora funciona muito bem. Os patches mais recentes dele podem ser encontrados aqui (para o Emacs 25.3) e aqui (para o ramo principal do Emacs).Eu vi boas melhorias no meu tempo de inicialização graças aos patches dele e estou em um ponto em que me sinto confortável com o meu tempo de inicialização, pois é o mais otimizado possível, sem cortar os recursos da minha personalização. Eu esperava que esses patches chegassem à linha principal do Emacs em algum momento, mas acho que eu (ou outra pessoa) teria que pegar a tocha agora, em vez de Stefan. Tivemos um pouco de dificuldade na lista de discussão sobre atribuição e licenciamento de direitos autorais. Inicialmente, fiquei desconfortável com isso, mas devido a alguns comentários de Richard Stallman e outros, a atribuição de direitos autorais pode não ser tão restritiva quanto eu pensava inicialmente. Além disso, pode ser possível eu comprometer meus trabalhos ao domínio público como alternativa à atribuição de direitos autorais.
De qualquer forma, obrigado Stefan pelos patches até agora! Espero que você continue desenvolvendo essas mudanças, mas se não, tudo bem e que eu possa continuar desenvolvendo em algum momento. Agradeço também a todos que ofereceram insights e contribuições para resolver esse problema.
Mais uma atualização:
Uau, parece que esse recurso finalmente chegou e estará no Emacs 27. Graças a Stefan Monnier!
use-package
é o caminho a percorrer para isso.Respostas:
Uma das opções de design no package.el foi tentar tornar as coisas "simples". Parte disso é que
package-initialize
procura todos os pacotes que estão instalados, depois tenta descobrir quais deles devem ser ativados (de acordo com a fixação e a evolução das versões no caso de várias versões do mesmo pacote) e carrega cada<pkg>-autoloads.el
arquivo do pacote de ativação .Portanto, para N pacotes instalados, isso significa basicamente ler N
<pkg>-pkg.el
arquivos de descrição de pacotes e N<pkg>-autoloads.el
arquivos. Para Ns grandes, isso pode se tornar um problema sério. Outro problema potencial de desempenho é que ele adiciona N elementos aload-path
, assim, toda vez que oload
Emacs pesquisa nos diretórios N, cada umload
fica mais lento.Existem várias maneiras de tentar acelerar isso:
Forneça uma maneira de pré-calcular um
~/.emacs.d/elpa/package-initialize.el(c)
arquivo que seria o resultado da concatenação de todos os direitos<pkg>-autoloads.el
na ordem certa. Depois,package-initialize
basta carregar esse arquivo quando presente e pular todo o resto. Você precisaria de alguma forma para atualizar / liberar opackage-initialize.el(c)
arquivo quando os pacotes forem adicionados / atualizados / removidos ou quando você alterar o seupackage-pinned-packages
ou o seupackage-load-list
. Eu acho que isso pode ser feito com poucas alterações no sistema (a única coisa que realmente precisaria ser alterada, acho que épackage-initialize
para que possa ser dito para "somente ativar" sem carregar os metadados dos pacotes disponíveis).Forneça uma maneira de criar / manipular super-pacotes, ou seja, pacote que combine vários pacotes em um (para que apenas um elemento seja adicionado
load-path
, um<pkg>-pkg.el
e um<pkg>-autoloads.el
carregado). Isso pode ser mais difícil de fazer (porque você não pode ativar apenas parte dos pacotes contidos nesses super-pacotes, portanto, a análise de dependência / versão pode ser complicada).A primeira opção acima deve ser bastante fácil de implementar e tornaria
package-initialize
muito mais rápida quando você tiver muitos pacotes instalados. Se você estiver interessado em experimentar, não hesite em me pedir ajuda.FWIW, eu apenas tentei criar um arquivo de mega-carregamento automático "manualmente" na minha configuração de teste. Resultados: enquanto
package-initialize
leva cerca de 0,9s, o carregamento domega-autoloads.el
arquivo leva 0,3s, que eu posso reduzir para 0,2s, ligandoload-source-file-function
para zero e para 0,1s, compilando o arquivo com byte. Eu esperava uma velocidade melhor, para ser honesto, mas ainda vale a pena.[EDIT] Esta abordagem de "mega carregamento automático" está agora disponível no ramo principal do Emacs (para se tornar o Emacs-27 em um futuro distante). É controlado pela nova
package-quickstart
variável.fonte
package.el
desenvolvedores. Que tipo de conselho você tem para começar com essa primeira opção? Eu gostaria de ver o que posso resolver com isso, pois parece muito mais viável.<pkg>-autoloads.el
arquivos configura apenas carregamentos automáticos e, de fato, não se preocupa com pedidos, mas não há nada que os impeça de fazer outras coisas aleatoriamente, e o package.el garante que o pacote do qual<pkg>
depende será ativado antes de<pkg>
si.O problema que você descreve sobre
package-initialize
levar tanto tempo para carregar é um problema bem conhecido. Esse também é um dos problemas que algumas estruturas do emacs tentam resolver carregando os carregamentos automáticos manualmente.Eu vejo duas soluções para o seu problema.
Uma das principais ressonâncias para recomendar o DOOM emacs é que a estrutura coloca o gerenciamento de pacotes fora do emacs. Não me interprete mal, ainda é o emacs que está fazendo o gerenciamento de pacotes, mas o gerenciamento de pacotes é feito fora de uma sessão de usuário padrão. A filosofia aqui é: ao iniciar o emacs normalmente, devemos assumir que todos os pacotes estão presentes e já podem ser carregados. Isso economiza muito tempo. O DOOM emacs fornece o equivalente a
apt-get
oupacman
para o emacs. Depois que um pacote é instalado, sempre que o emacs inicia, presume-se que ele já esteja instalado; sem perguntas.fonte