O que posso fazer para acelerar minha inicialização?

41

Quais são algumas das coisas básicas que eu poderia fazer para reduzir o tempo de inicialização?

Há algo em particular no qual devo prestar atenção, nesse caso?

Nota: O tempo de inicialização pode ser atenuado iniciando o Emacs com menos frequência (uma vez por sessão) e abrindo arquivos em uma instância em execução . Esta pergunta é sobre como minimizar o tempo de inicialização, para o início da sessão ou qualquer outro momento em que o Emacs for necessário.


Veja também a mesma pergunta respondida no Stack Overflow, com pontuações de perguntas e respostas acima de 50 e 30 - alguns favoritos "favoritos". Boas respostas aqui devem ir além do que está disponível no Stack Overflow.

caisah
fonte
11
Eu adoraria ter dados sobre isso, mas meu palpite é que, para a maioria dos usuários, existe um ou dois pacotes que contribuem para a maior parte do tempo de inicialização. No meu caso, era leme. Observe que, se você usar o helm, não poderá adiar sua inicialização, deseje que ele esteja pronto para uso imediato. Eu mudei para a hera e isso reduziu minha hora de início de cerca de 12 segundos para menos de um segundo. Eu até parei de usar a configuração do servidor / cliente. (By the way, eu não mudar para reduzir o tempo de inicialização, que era apenas um benefício agradável lado.)
Omar

Respostas:

43

Aqui estão os meus pontos de redução emacs-init-time: isso não cobre coisas como o uso de um daemon ou servidor, nem é preciso dizer que você raramente deve fechar o emacs.

Não faça:

  • Não exija pacotes no seu init, se o pacote não tiver cookies de carregamento automático adequados, verifique se você configurou os carregamentos automáticos nos comandos de entrada. Portanto, se a primeira vez que você usar o pacote foobarfor chamar foobar-modee foobarnão tiver sido pré-carregado automaticamente, você precisará de algo como isto:

    (autoload 'foobar-mode "foobar")
    

    isso permitirá que você ligue foobar-modemesmo quando o foobarpacote ainda não foi carregado. Dessa forma foobar, não será carregado até que você realmente liguefoobar-mode

  • Não execute package-refresh-contentsse você não precisar instalar pacotes na inicialização. Se o init está configurado para instalar automaticamente pacotes ausentes, considere configurar um argumento de linha de comando para especificar quando a instalação automática deve ocorrer.

  • Como acima, não faça nada relacionado à rede.
  • Não carregue seu desktopon init a menos que você realmente queira.

Faz

  • Use algo como use-packagepara gerenciar seus pacotes. Isso facilita a especificação do que exigir, o que carregar posteriormente, o que carrega automaticamente o que e facilita a criação de perfil do seu init em um pacote por pacote.

  • Conheça a diferença entre carregar e habilitar um tema. Em resumo, você pode carregar quantos quiser, mas verifique se não está ativando mais de um. Idealmente, carregue e ative apenas um tema. load-themeprecisa de um argumento opcional para impedir a ativação do tema. Pode ser fácil ativar acidentalmente vários temas, que são lentos e feios durante a inicialização.

  • Faça truques: Muitas vezes existem modos globais grandes que você deseja carregar no init, coisas como desfazer árvore, preenchimento automático, modo ido etc. Certifique-se de que as funções de entrada tenham configuração de carregamento automático e inicie temporizadores inativos no init para carregar os pacotes . Eu faço isso undo-tree-mode, idoe outros, e nunca noto um atraso, porque no momento em que realmente preciso usá-los, eles já estão carregados.

    Atualização: use-package mudou um pouco, leia o leia-me oficial antes de começar a usar os recursos do timer.

    Por exemplo: se você quiser atrasar um pouco o carregamento, global-undo-tree-modepoderá colocar isso no seu init:

    (run-with-idle-timer 1 nil (lambda () (global-undo-tree-mode t)))
    

    Agora, o seu init pode continuar feliz e global-undo-tree-modenão será ativado até que tudo esteja pronto e você esteja ao volante.

    use-packagetem suporte para esse tipo de comportamento incorporado usando a palavra-chave: idle. Aqui está a undo-treeconfiguração do meu .init.el:

    (use-package undo-tree
      :idle (global-undo-tree-mode 1)
      :bind (("C-c j" . undo-tree-undo)
             ("C-c k" . undo-tree-redo)
             ("C-c l" . undo-tree-switch-branch)
             ("C-c ;" . undo-tree-visualize))
      :ensure t)
    
  • Faça o perfil do seu init, é sempre surpreendente ver onde estão as lentidões reais. profile-dotemacs.el é uma ferramenta incrível que eu usei para me ajudar a diminuir meu init de ~ 6 segundos para <1 segundo.

Um use-packageinit bem configurado pode ser incrivelmente rápido. Eu não compto com byte meu init e ele usa use-packagepara configurar 95 pacotes e inicia em <1 segundo.

Jordon Biondo
fonte
7
"Crie um perfil do seu init, é sempre surpreendente ver onde estão as lentidões reais." Alerta de spoiler, é essa (require 'org)linha. :-)
Malabarba
@ Jordânia, você poderia estender um pouco a maneira de garantir que as funções de entrada tenham configuração de carregamento automático e iniciar temporizadores inativos no seu init para carregar os pacotes, em particular no modo desfazer árvore? Obrigado.
Francisco Dibar
@FranciscoDibar Atualizei meu post com exemplos.
Jordon Biondo 17/10
2
Eu uso o modo ido imediatamente, Cx Cf ou Mx para smex é a primeira coisa que quase sempre quando abro o emacs, e nunca notei um problema. Além disso, se você quiser desfazer algo dentro de um segundo da abertura do emacs ... Bem, não tenho nada a dizer sobre isso. Se você está realmente preocupado, experimente você mesmo ou use um cronômetro não ocioso ou o gancho de inicialização.
21413 Jordon Biondo
11
A sugestão de timer ocioso é útil. Uma sintaxe de carregamento um pouco mais curta é (run-with-idle-timer 1 nil #'global-undo-tree-mode)'. If the function you are loading takes parameters you can just provide them after the o comando # ''.
Andrew Swann
8

Algo que apareceu recentemente no emacs reddit : diminua o número de chamadas de coleta de lixo colocando isso perto do início do seu arquivo init:

(setq gc-cons-threshold 50000000)

(add-hook 'emacs-startup-hook 'my/set-gc-threshold)
(defun my/set-gc-threshold ()
  "Reset `gc-cons-threshold' to its default value."
  (setq gc-cons-threshold 800000))

No exemplo acima, o GC é chamado a cada ~ 50MB (em vez do padrão de ~ 800kb), o que parece sensato em um sistema moderno com bastante RAM.

ffevotte
fonte
11
Exceto que o valor é (a) provavelmente muito maior do que você precisa (não vejo diferença em um décimo disso); e (b) evidentemente, não é um valor que você deseja persistir além da inicialização, porque um limite grande de GC equivale a atrasos maiores sempre que o GC acontece. Se você definir alto para o init, diminua novamente após o init. Eu acho que emacs-startup-hooké um bom lugar para fazer isso.
phils
11
@phils Obrigado! (a) Na minha configuração, 50Mb fornece o número mínimo de GCs (e o tempo mínimo de inicialização). Se eu chegar aos 10Mb, a diferença é perceptível / mensurável (embora não mude muito na prática ...) (b) boa ideia, obrigado. Editei a postagem para refletir seu comentário.
Ffevotte 15/09/2015
6

O tempo gasto na otimização do tempo de inicialização provavelmente será maior do que todo o tempo extra que você esperaria que o Emacs iniciasse.

No momento, faço 25 requirechamadas no meu arquivo init para que o Flycheck possa encontrar erros de ortografia no meu código. Meu horário de inicialização é ...

$ time emacs --eval '(save-buffers-kill-terminal)'

real    0m2.776s
user    0m2.305s
sys     0m0.148s

Além disso, no meu sistema, time emacs -Q --eval '(save-buffers-kill-terminal)'tem um realdos 0m0.404s. O tempo máximo teórico que posso economizar é de 2,3 segundos.

Digamos que passo uma hora fazendo todas as otimizações no meu arquivo init. (Não contarei os 15-30 minutos adicionais gastos em uma data posterior tentando descobrir por que minhas alterações não estavam entrando em vigor devido ao fato de meu arquivo init ter sido compilado em bytes.) (Também não contarei o tempo em que O Flycheck teria me poupado no depurador se eu não tivesse removido as requirechamadas.) Há 3600 segundos em uma hora; portanto, se eu conseguisse salvar os 2,3 segundos inteiros, meu investimento em tempo só valeria a pena após 1565 inicializações.

Supondo que eu reiniciei o Emacs 3 vezes por dia, todos os dias, levaria um ano e meio para que esse investimento valesse a pena. Se eu deixasse a mesma instância do Emacs em execução por dias seguidos (como sempre faço), provavelmente reiniciaria apenas de 2 a 5 vezes por semana; nesse caso, levaria de 6 a 15 anos para que o investimento valesse a pena.

Estou sendo generoso, porque é provável que você gaste mais de uma hora otimizando sua inicialização e provavelmente não salvará o número teórico máximo de segundos.

Jackson
fonte
12
Mas você potencialmente será mais feliz.
phils
2
Isso pode ser verdade para uma pessoa, mas o objetivo do StackExchange é o compartilhamento. Que tal um truque que leva 30 minutos para uma pessoa encontrar, mas reduz 1 segundo do tempo de inicialização de dezenas de pessoas? Você ainda consideraria um investimento ruim?
ffevotte
@phils Ironicamente, pensei em dizer a mesma coisa, mas em apoio ao meu próprio ponto de vista! "Antes de você gemer sobre o tempo de inicialização, pense: 'Estou feliz por não ter perdido tempo otimizando isso!'"
Jackson
@Francesco E este post é o meu truque que economiza tempo para dezenas de pessoas.
Jackson Jackson
@ Jackson Eu ainda não concordo com você nesta questão em particular, mas pelo menos agora entendo o seu ponto. Obrigado :)
ffevotte 14/09/15