Что я могу сделать, чтобы ускорить мой запуск?

41

Какие основные вещи я могу сделать, чтобы сократить время запуска?

Есть ли на что-то особенное, на что я должен обратить внимание?

Примечание: Время запуска можно уменьшить, реже запуская Emacs (один раз за сеанс) и открывая файлы в работающем экземпляре . Этот вопрос касается минимизации времени запуска, начала сеанса или любого другого времени, когда необходим запуск Emacs.


См. Также тот же вопрос, на который дан ответ в Stack Overflow, с оценками вопросов и ответов более 50 и 30 с некоторыми «любимыми» закладками. Хорошие ответы здесь должны выходить за рамки того, что доступно в переполнении стека.

caisah
источник
1
Я хотел бы иметь данные по этому вопросу, но я предполагаю, что для большинства пользователей есть один или два пакета, которые составляют основную часть времени запуска. В моем случае это был руль. Обратите внимание, что если вы используете helm, вы не можете отложить его инициализацию, вы хотите, чтобы он был готов к немедленному использованию. Я переключился на плющ, и это уменьшило мое время старта с 12 до менее секунды. Я даже перестал использовать настройки сервера / клиента. (Кстати, я не стал сокращать время запуска, это было просто приятным побочным эффектом.)
Омар

Ответы:

43

Вот мои замечания по сокращению emacs-init-time, это не распространяется на такие вещи, как использование демона или сервера, само собой разумеется, что вы редко когда-либо закрываете emacs.

Не рекомендуется:

  • Не требуйте пакетов в вашей инициализации, если пакет не имеет надлежащих файлов автозагрузки, убедитесь, что вы настроили автозагрузку в командах ввода. Так что, если вы в первый раз используете package foobarпри вызове, foobar-modeа foobarон не был предварительно загружен, вам понадобится что-то вроде этого:

    (autoload 'foobar-mode "foobar")
    

    это позволит вам звонить, foobar-modeдаже если foobarпакет еще не был загружен. Этот способ foobarне будет загружен, пока вы на самом деле не позвонитеfoobar-mode

  • Не запускайте, package-refresh-contentsесли вам не нужно устанавливать пакеты при запуске. Если ваш init настроен на автоматическую установку отсутствующих пакетов, рассмотрите возможность установки аргумента командной строки, чтобы вы могли указать, когда должна происходить автоматическая установка.

  • Как и выше, не делайте ничего, связанного с сетью.
  • Не загружайте свой файл desktopinit, если вы действительно этого не хотите.

Делать

  • Используйте что-то вроде use-packageуправления своими пакетами. Это позволяет легко указать, что требуется, что загружать позже, что загружать автоматически и что упрощает профилирование вашего init для каждого пакета.

  • Знайте разницу между загрузкой темы и ее включением. Короче говоря, вы можете загрузить столько, сколько хотите, но убедитесь, что вы не включаете более одного. В идеале загружайте и включайте только одну тему. load-themeнужен необязательный аргумент arg для предотвращения включения темы. Может быть легко случайно включить несколько тем, что медленно и безобразно во время запуска.

  • Делать чит: часто бывают большие глобальные режимы, которые вы хотите загрузить при инициализации, такие как отмена дерева, автозаполнение, режим ido и т. Д. Убедитесь, что у функций ввода есть настройка автозагрузки, затем запустите таймеры простоя в вашем init для загрузки пакетов , Я делаю эту волю undo-tree-mode, idoи другие и никогда не замечают задержку , потому что к тому времени , я на самом деле нужно использовать их, они уже загружены.

    Обновление: use-package немного изменился, прочитайте официальный readme перед тем, как начать использовать функции таймера.

    Например: если вы хотите немного отложить загрузку, global-undo-tree-modeвы можете поместить это в свой init:

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

    Теперь ваша инициализация может продолжаться счастливо и global-undo-tree-modeфактически не будет активирована, пока все остальное не будет готово, и вы не сядете за руль.

    use-packageимеет поддержку такого поведения, встроенную с помощью ключевого слова: idle. Вот undo-treeконфиг из моего .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)
    
  • Сделайте профиль вашей инициации, всегда удивительно видеть, где реальные замедления. profile-dotemacs.el - это невероятный инструмент, который я использовал, чтобы помочь мне снизить скорость инициализации с ~ 6 секунд до <1 секунды.

Хорошо сконфигурированный use-packageinit может быть невероятно быстрым. Я не байт-компилирую свой init, и он использует use-packageдля настройки 95 пакетов и запускается через <1 секунду.

Джордон Биондо
источник
7
«Сделайте профиль своего инициата, всегда удивительно видеть, где реальные замедления». Оповещение спойлера, это та (require 'org)линия. :-)
Малабарба
@ Джордан, не могли бы вы рассказать немного о том, как убедиться, что у функций ввода есть настройка автозагрузки, а затем запустить таймеры простоя в вашем init для загрузки пакетов, в частности, для режима отмены дерева? Спасибо.
Франциско Дибар
@FranciscoDibar Я обновил свой пост с примерами.
Джордон Биондо
2
Я немедленно использую режим ido, Cx Cf или Mx для smex - это первое, что я почти всегда делаю, когда открываю emacs, и я никогда не замечал проблем. Также, если вы хотите отменить что-то в течение секунды после открытия emacs ... Ну, мне нечего сказать по этому поводу. Если вас это действительно беспокоит, попробуйте сами, или просто используйте неактивный таймер или после ловушки init.
Джордон Биондо
1
Предложение таймера простоя полезно. Немного более короткий синтаксис загрузки - (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 команда #.
Эндрю Суонн
8

Что-то, что недавно появилось в emacs reddit : уменьшите количество вызовов сборки мусора, поместив это в начале вашего файла инициализации:

(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))

В приведенном выше примере GC вызывается каждые ~ 50 МБ (вместо значения по умолчанию ~ 800 КБ), что представляется разумным в современной системе с большим количеством оперативной памяти.

ffevotte
источник
1
За исключением того, что значение (а), вероятно, намного выше, чем вам нужно (я не вижу разницы с одной десятой этого); и (b) явно не значение, которое вы хотите сохранить после запуска, потому что большой порог GC означает более длительные задержки всякий раз, когда происходит GC. Если вы установили высокий уровень для init, снова установите его ниже после init. Я думаю, что emacs-startup-hookэто хорошее место для этого.
Филс
1
@phils Спасибо! (a) На моей установке, 50Mb дает минимальное количество GC (и минимальное время запуска). Если я пройду до 10 Мб, разница будет заметна / ощутима (хотя на практике не сильно изменится ...) (б) хорошая идея, спасибо. Я отредактировал пост, чтобы отразить ваш комментарий.
ffevotte
6

Время, которое вы тратите на оптимизацию времени запуска, вероятно, будет больше, чем все дополнительное время, которое вы ожидали бы при запуске Emacs.

На данный момент я делаю 25 requireвызовов в моем файле инициализации, чтобы Flycheck мог найти орфографические ошибки в моем коде. Мое время запуска ...

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

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

Кроме того, в моей системе time emacs -Q --eval '(save-buffers-kill-terminal)'есть realиз 0m0.404s. Теоретическое максимальное количество времени, которое я могу сэкономить, составляет 2,3 секунды.

Скажем, я потратил час на внесение изменений в мой файл инициализации. (Я не буду считать дополнительные 15-30 минут, потраченные на более позднюю дату, пытаясь выяснить, почему мои изменения не вступили в силу из-за того, что мой файл инициализации был побитно скомпилирован.) (Я также не буду считать время, которое Flycheck спас бы меня в отладчике, если бы я не удалял requireвызовы.) В часе 3600 секунд, поэтому, если бы мне удалось сэкономить все 2,3 секунды, мои затраты на время окупились бы только после 1565 запусков.

Предполагая, что я перезапускаю Emacs 3 раза в день, каждый день, чтобы эти инвестиции окупились, понадобится полтора года. Если бы я оставлял один и тот же экземпляр Emacs на несколько дней подряд (как я это часто делаю), я бы, вероятно, перезапускал только 2-5 раз в неделю, и в этом случае эти инвестиции окупились бы от 6 до 15 лет.

Я щедрый, потому что вы, скорее всего, потратите больше часа на оптимизацию своего стартапа, и вы, вероятно, не сэкономите максимальное теоретическое количество секунд.

Джексон
источник
12
Но вы потенциально будете счастливее.
Филс
2
Это может быть правдой для одного человека, но весь смысл StackExchange заключается в обмене. Как насчет трюка, который занимает 30 минут, чтобы найти одного человека, но экономит 1 секунду от времени запуска десятков людей? Вы все еще считаете это плохой инвестицией?
ffevotte
@phils По иронии судьбы, я подумал сказать то же самое, но в поддержку своей собственной точки зрения! «Прежде чем стонать о времени запуска, подумайте про себя:« Я рад, что не стал тратить время на оптимизацию этого! »
Джексон
@Francesco И этот пост - мой трюк, который экономит время десятков людей.
Джексон
@ Джексон Я все еще не согласен с вами по этому конкретному вопросу, но, по крайней мере, теперь я понимаю вашу точку зрения. Спасибо :)
ffevotte