Как я могу улучшить время запуска, несмотря на множество пакетов?

19

TL; DR У меня такое огромное количество пакетов, что это мешает моему запуску. Если вы не верите в это, читайте дальше.


Время запуска моего Emacs довольно мало. Я не пользуюсьuse-package , я просто установил тонны хуков и autoloads, чтобы почти весь код был отложен. На самом деле все загружается менее чем за полсекунды, несмотря на то, что это выглядит как сумасшедший беспорядок.

Тем не менее, со временем я заметил, что мое время запуска становится немного медленнее, необъяснимым образом. Это в конечном итоге дошло до того, что время запуска ≥ 1 секунды. Мне наконец то надоело и я в корне закопался в проблеме. В конце концов я закомментировал весь ~/.emacsфайл и обнаружил, что время запуска все еще составляло ≥ 1 секунды. На самом деле, он только сбрил ~ 0.2секунды, иногда даже меньше. Затем я попытался emacs -qи обнаружил, что время запуска было ~0.1 секунд.

Изучив этот раздел руководства Elisp, я выяснил, почему emacs -qтак сильно сокращается время запуска. По-видимомуemacs -q мешает Emacs делать три вещи при запуске:

  1. загрузка вашего файла инициализации
  2. загружая ваш default.el файла
  3. призвание package-initialize

Мы уже исключили мой файл инициализации, поскольку комментирование всего моего файла ~/.emacsпочти ничего не делает. Я не использую default.elфайл, так что это также исключено. Который оставляет package-initializeв качестве виновника удара производительности.

Зачем package-initializeзанимать так много времени запуска? Это был первый вопрос, который я задал себе. Разве я не загружаю все? Ну да. Но это именно проблема.

Я нашел этот пост который объясняет, что «активация» пакетов состоит из чтения файлов автозагрузки и установки путей загрузки. Это, очевидно, влечет за собой штраф ввода-вывода, когда у вас много пакетов, потому что у вас есть много файлов автозагрузки для чтения и множество путей для установки. К сожалению, без этого задача управления автозагрузками попадает в руки пользователя. Другими словами, не позволяя package.elсканировать файловую систему для автозагрузки файлов и путей, мне пришлось бы самому управлять этим, что может быть утомительным и подверженным ошибкам процессом.

Я бы предпочел не идти по этому пути. В настоящее время у меня 116 пакетов, из которых 107 из ELPA и 25 из которых являются зависимостями. Я уверен, что это колоссальное число - то, что так сильно ухудшает мою производительность. Но я в затруднительном положении, потому что я не хочу удалять ни один из своих пакетов.

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


Обновить:

Мы начали новый поток на emacs-develсписок рассылки о некоторых пластырей по Стефан Монье (описание этих патчей здесь ) , чтобы решить эту проблему. Любой желающий может проверить свои патчи и дать отзыв.

Еще одно обновление:

Похоже, что Стефан Моннье либо не заинтересован в этом вопросе, либо не получает мои сообщения. Я склонен верить первому, что хорошо, хотя я был бы признателен за какой-то ответ от него, если это так. Во всяком случае, код, который он создал для этой проблемы, пока работает довольно хорошо. Самые последние его патчи можно найти здесь (для Emacs 25.3) и здесь (для основной ветки Emacs).Благодаря его исправлениям я увидел хорошие улучшения во время запуска, и теперь я чувствую себя комфортно со временем запуска, так как оно максимально оптимизировано без потери возможностей моей настройки. Я надеялся, что эти патчи в какой-то момент попадут в магистраль Emacs, но я думаю, что мне (или кому-то еще) придется вместо этого взять факел вместо Стефана. У нас был небольшой спар в списке рассылки о передаче авторских прав и лицензировании. Сначала я чувствовал себя неловко, но из-за некоторых комментариев Ричарда Столлмана и других авторское право может быть не таким ограничительным, как я первоначально думал. Более того, для меня может быть возможность передать свои работы в общественное достояние в качестве альтернативы передаче авторских прав.

В любом случае, спасибо Стефану за патчи! Я надеюсь, что вы продолжите развивать эти изменения, но если нет, то все в порядке, и я могу продолжить развивать их в какой-то момент. Я также благодарю всех, кто предложил понимание и вклад в решение этой проблемы.

Еще одно обновление:

Ух ты, похоже, эта функция наконец-то появилась и будет в Emacs 27. Спасибо Стефану Моннье!

ВВП2
источник
Отличный вопрос
Дрю
use-packageэто способ пойти на это.
Доджи
Не пытайтесь преуменьшить проблему (задержка запуска важна!), Но рассмотрите возможность запуска emacs в качестве демона / сервера, чтобы вы оплачивали только стоимость запуска один раз.
GManNickG
1
@GManNickG Я запускаю Emacs как сервер. К сожалению, время от времени я слишком сильно толкаю Emacs или слишком много с ним работаю, и перезапуск - лучший способ убрать вещи. Когда это происходит, мне нравится, чтобы мое время запуска было оптимальным.
GDP2

Ответы:

13

Один из вариантов дизайна в package.el - попытаться сделать вещи «простыми». Часть этого заключается в том, что package-initializeищет все пакеты, которые установлены, затем пытается выяснить, какие из них следует активировать (в зависимости от закрепления и недавности версий в случае, если доступно несколько версий одного и того же пакета), затем загружает каждый активировать <pkg>-autoloads.elфайл пакета .

Таким образом, для N установленных пакетов это означает в основном чтение N <pkg>-pkg.elфайлов описания пакетов и N <pkg>-autoloads.elфайлов. Для больших Ns это может стать серьезной проблемой. Другая потенциальная проблема производительности - добавление N элементов load-path, поэтому каждый раз, когда вы, loadEmacs, будете искать в N каталогах, каждый из loadних замедляется.

Есть несколько способов ускорить это:

  • Предоставьте какой-нибудь способ предварительного вычисления ~/.emacs.d/elpa/package-initialize.el(c)файла, который будет результатом объединения всех прав <pkg>-autoloads.elв правильном порядке. Затем package-initializeможно просто загрузить этот файл, когда он есть, и пропустить все остальное. Затем вам понадобится какой-нибудь способ обновить / очистить package-initialize.el(c)файл, когда пакеты добавляются / обновляются / удаляются или когда вы меняете свой package-pinned-packagesили свой package-load-list. Я думаю, что это можно сделать с помощью довольно небольшого количества изменений в системе (я думаю, package-initializeчто единственное, что действительно нужно было бы изменить, так это то, что его можно сказать «только активировать» без загрузки метаданных о доступных пакетах).

  • Обеспечить некоторый способ создания / манипулирования суперпакетами, то есть пакетами, которые объединяют несколько пакетов в один (так что добавляется только один элемент load-path, загружается один <pkg>-pkg.elи один <pkg>-autoloads.el). Это может быть более трудным для выполнения (потому что тогда вы не можете активировать только часть пакетов, содержащихся в таких супер-пакетах, поэтому анализ зависимости / версии может быть сложным).

Первый вариант, описанный выше, должен быть довольно простым для реализации и работать package-initialize намного быстрее, если у вас установлено много пакетов. Если вы заинтересованы в этом, не стесняйтесь обратиться ко мне за помощью.

FWIW, я только что попытался создать такой файл мега-автозагрузки "вручную" на моей тестовой установке. Результаты: в то время как package-initializeзагрузка занимает около 0,9 с, загрузка mega-autoloads.elфайла занимает 0,3 с, что я могу уменьшить до 0,2 с, привязав let load-source-file-functionк nil, и до 0,1 с путем байтовой компиляции файла. Честно говоря, я ожидал лучшего ускорения, но оно того стоит.

[EDIT] Этот подход "мега автозагрузки" теперь доступен в основной ветке Emacs (чтобы стать Emacs-27 в некотором отдаленном будущем). Это контролируется новой package-quickstartпеременной.

Стефан
источник
Это очень интересные идеи. Первый звучит более приземленно и не так сложно. Второй довольно интересный, но звучит как работа для package.elразработчиков. Какой совет вы бы дали, начав с первого варианта? Я хотел бы посмотреть, что я могу с этим сделать, так как это кажется гораздо более работоспособным.
GDP2
el-get использует подход с одним файлом автозагрузки, в основном он работает большую часть времени. Есть проблемы с некоторыми пакетами, автозагрузка которых зависит от расположения в файловой системе, в которой они оцениваются. Однако я не понимаю, что вы подразумеваете под «в правильном порядке», почему порядок загрузки автозагрузки имеет значение (я не сделал думаю, что это было даже детерминировано для текущего package.el)?
npostavs
@ Стефан, пожалуйста, поделитесь решением здесь, если это возможно.
Мануэль Уберти
1
@npostavs: большинство <pkg>-autoloads.elфайлов только устанавливают автозагрузку и, в действительности, не заботятся о порядке, но ничто не мешает им делать другие случайные вещи, а package.el гарантирует, что пакет, от которого <pkg>зависит, будет активирован раньше <pkg>самого себя.
Стефан
1
Еще одно обновление по этой проблеме: мы начали новую тему в списке рассылки здесь и любой может свободно комментировать или тестировать изменения Стефана.
GDP2
6

Проблема, которую вы описываете из-за package-initializeтого, что загружается так много времени, является хорошо известной. Это также одна из проблем, которую некоторые фреймворки emacs пытаются решить, загружая автозагрузки вручную.

Я вижу два решения вашей проблемы.

  1. Напишите (или извлеките из фреймворка) функциональность, чтобы установить пути и загрузить автозагрузки интересующих вас пакетов.
  2. Используйте структуру, которая явно нацелена на скорость. Я лично рекомендую DOOM Emacs . С помощью этого фреймворка я загружаю более 200 пакетов примерно за 1 секунду.

Одним из главных доводов в пользу рекомендации DOOM emacs является то, что инфраструктура выводит управление пакетами за пределы emacs. Не поймите меня неправильно, управление пакетами по-прежнему выполняет emacs, просто управление пакетами выполняется вне стандартного пользовательского сеанса. Философия здесь такова: при нормальном запуске emacs мы должны предполагать, что все пакеты присутствуют и уже могут быть загружены. Это экономит много времени. DOOM Emacs обеспечивает своего рода эквивалент apt-getили pacmanдля Emacs. После того, как пакет установлен, при запуске emacs предполагается, что он уже установлен; никаких вопросов не было задано.

UndeadKernel
источник
Фу, рад знать, что этот вопрос касается не только меня. Спасибо, что указали мне на DOOM Emacs. Я должен поближе взглянуть на это и посмотреть, что я могу адаптировать к своим собственным настройкам.
GDP2
Я играю с DOOM emacs (и помогаю, когда могу) уже некоторое время. Если у вас возникли проблемы, не стесняйтесь связаться со мной.
UndeadKernel