Wie kann ich die Startzeit trotz vieler Pakete verbessern?

19

TL; DR Ich habe so viele Pakete, dass meine Startzeit darunter leidet. Wenn Sie nicht glauben, dass dies der Fall sein könnte, lesen Sie weiter.


Meine Emacs-Startzeit ist ziemlich kurz. Ich benutze es nicht use-package, ich setze einfach autoloadjede Menge Hooks und s, so dass fast der gesamte Code zurückgestellt wird. In Wirklichkeit ist das Ganze in weniger als einer halben Sekunde geladen, obwohl es wie eine verrückte Sauerei aussieht.

Mit der Zeit bemerkte ich jedoch, dass meine Startzeit aus unerklärlichen Gründen geringfügig langsamer wird. Dies hat irgendwann den Punkt erreicht, an dem die Startzeit ≥ 1 Sekunde ist. Ich hatte endlich genug und grub mich in die Wurzel des Problems. Schließlich habe ich meine gesamte ~/.emacsDatei auskommentiert und festgestellt, dass die Startzeit immer noch ≥ 1 Sekunde war. Tatsächlich hatte es sich nur wenige 0.2Sekunden rasiert , manchmal sogar weniger. Dann habe ich versucht emacs -qund festgestellt, dass die Startzeit ~ 0.1Sekunden war.

Beim Durchsuchen dieses Abschnitts des Elisp-Handbuchs habe ich herausgefunden, warum emacs -qdie Startzeit so stark reduziert wurde. Hält emacs -qEmacs anscheinend davon ab, beim Start drei Dinge zu tun:

  1. Laden Sie Ihre Init-Datei
  2. Laden Sie Ihre default.elDatei
  3. Berufung package-initialize

Wir haben meine Init-Datei bereits ausgeschlossen, da das Auskommentieren meiner gesamten Datei ~/.emacsfast nichts bewirkt. Ich verwende keine default.elDatei, daher ist das auch ausgeschlossen. Was package-initializeals Täter für den Performance-Hit übrig bleibt .

Warum würde package-initializeso viel Startzeit in Anspruch nehmen? Das war die erste Frage, die ich mir gestellt habe. Lade ich nicht alles automatisch? Nun ja. Aber das ist genau das Problem.

Ich habe diesen Beitrag gefunden, in dem erklärt wird, dass das Aktivieren von Paketen darin besteht, Autoload-Dateien zu lesen und Ladepfade festzulegen. Dies führt offensichtlich zu einer E / A-Beeinträchtigung, wenn Sie viele Pakete haben, da Sie viele Autoload-Dateien lesen und viele Pfade festlegen müssen. Ohne dies fällt die Verwaltung von Autoloads leider in die Hände des Benutzers. Mit anderen Worten, ohne package.eldas Dateisystem nach Autoload-Dateien und -Pfaden durchsuchen zu lassen, müsste ich das selbst verwalten, was ein mühsamer und fehleranfälliger Prozess sein könnte.

Ich würde es vorziehen, diesen Weg nicht zu gehen. Ich habe derzeit 116 Pakete, von denen 107 von ELPA und 25 von Abhängigkeiten sind. Ich bin mir sicher, dass diese unglaubliche Zahl meine Leistung so stark beeinträchtigt. Aber ich bin in einem Dilemma, weil ich keines meiner Pakete entfernen möchte.

Gibt es in einer solchen Situation Abhilfe, um meine Blitzstartzeit wieder herzustellen?


Aktualisieren:

Wir haben einen neuen Thread in der emacs-develMailingliste über einige Patches von Stefan Monnier gestartet (eine Beschreibung dieser Patches finden Sie hier ), um dieses Problem zu lösen. Jeder kann seine Patches testen und Feedback geben.

Ein weiteres Update:

Es scheint, dass Stefan Monnier sich entweder nicht mehr für dieses Thema interessiert oder meine Nachrichten nicht mehr erhält. Ich neige dazu, das erstere zu glauben, was in Ordnung ist, obwohl ich eine Art Antwort von ihm begrüßen würde, wenn dies der Fall ist. Wie auch immer, der Code, den er bisher für diese Ausgabe erstellt hat, funktioniert ganz gut. Die neuesten Patches von ihm finden Sie hier (für Emacs 25.3) und hier (für Emacs master branch).Ich habe dank seiner Patches eine gute Verbesserung meiner Startzeit festgestellt und bin an einem Punkt angelangt, an dem ich mit meiner Startzeit insofern zufrieden bin, als sie so optimiert wie möglich ist, ohne die Funktionen meiner Anpassung zu beeinträchtigen. Ich hatte gehofft, dass diese Patches es irgendwann in die Emacs-Mainline schaffen würden, aber ich denke, dass ich (oder jemand anderes) jetzt die Fackel dafür nehmen müsste, anstatt Stefan. Wir hatten einige Probleme mit der Zuweisung von Urheberrechten und der Lizenzierung auf der Mailingliste. Anfangs war mir das unangenehm, aber aufgrund einiger Kommentare von Richard Stallman und anderen ist die Urheberrechtszuweisung möglicherweise nicht so restriktiv, wie ich ursprünglich dachte. Es kann mir auch möglich sein, meine Werke als Alternative zur Übertragung von Urheberrechten gemeinfrei zu machen.

Auf jeden Fall danke Stefan für die bisherigen Patches! Ich hoffe, Sie werden diese Änderungen weiterentwickeln, aber wenn nicht, ist das in Ordnung und ich werde sie möglicherweise irgendwann weiterentwickeln. Ich danke auch allen anderen, die Einblicke und Beiträge zur Lösung dieses Problems geleistet haben.

Noch ein Update:

Wow, sieht so aus, als wäre dieses Feature endlich gelandet und wird in Emacs 27 sein. Danke an Stefan Monnier!

GDP2
quelle
Gute Frage.
Drew
use-packageist der richtige Weg dafür.
Dodgie
Versuchen Sie nicht, das Problem herunterzuspielen (Startverzögerung ist wichtig!), Aber ziehen Sie in Betracht, Emacs als Dämon / Server auszuführen, damit Sie nur einmal die Startkosten bezahlen.
GManNickG
1
@GManNickG Ich führe Emacs als Server aus. Leider drücke ich ab und zu Emacs zu fest oder bastle zu viel daran und ein Neustart ist der beste Weg, die Dinge aufzuräumen. In diesem Fall möchte ich, dass meine Startzeit optimal ist.
GDP2

Antworten:

13

In package.el wurde unter anderem versucht, die Dinge "einfach" zu gestalten. Dazu gehört, dass package-initializenach allen installierten Paketen gesucht wird und dann versucht wird, herauszufinden, welche davon aktiviert werden sollten (je nach Pinning und Aktualität der Versionen, falls mehrere Versionen desselben Pakets verfügbar sind). Anschließend wird das Paket geladen jedes aktiviere die <pkg>-autoloads.elDatei des Pakets .

Für N installierte Pakete bedeutet dies, dass grundsätzlich N <pkg>-pkg.elPaketbeschreibungsdateien und N <pkg>-autoloads.elDateien gelesen werden. Für große Ns kann dies ein ernstes Problem werden. Ein weiteres mögliches Leistungsproblem besteht darin, dass N Elemente hinzugefügt load-pathwerden. Jedes Mal, wenn loadEmacs N Verzeichnisse durchsucht , wird jedes Element loadverlangsamt.

Es gibt verschiedene Möglichkeiten, dies zu beschleunigen:

  • Stellen Sie eine Möglichkeit bereit, eine ~/.emacs.d/elpa/package-initialize.el(c)Datei vorab zu berechnen , die das Ergebnis der Verkettung aller Rechte <pkg>-autoloads.elin der richtigen Reihenfolge wäre. Dann package-initializekönnte man einfach diese Datei laden wenn vorhanden und alles andere überspringen. Sie benötigen dann eine Möglichkeit, die package-initialize.el(c)Datei zu aktualisieren / zu leeren, wenn Pakete hinzugefügt / aktualisiert / entfernt werden oder wenn Sie Ihre package-pinned-packagesoder Ihre ändern package-load-list. Ich denke, dies kann mit relativ wenigen Änderungen am System durchgeführt werden (das einzige, was meiner Meinung nach wirklich geändert werden müsste, ist package-initialize, dass es angewiesen wird, "nur zu aktivieren", ohne die Metadaten über verfügbare Pakete zu laden).

  • Bieten Sie eine Möglichkeit zum Erstellen / Bearbeiten von Super-Paketen, dh Paketen, die mehrere Pakete zu einem kombinieren (sodass nur ein Element hinzugefügt load-path, eins <pkg>-pkg.elund eins <pkg>-autoloads.elgeladen wird). Dies ist möglicherweise schwieriger durchzuführen (da Sie dann nicht nur einen Teil der in solchen Super-Paketen enthaltenen Pakete aktivieren können, sodass die Abhängigkeits- / Versionsanalyse schwierig sein kann).

Die erste obige Option sollte ziemlich einfach zu implementieren sein und package-initialize viel schneller sein, wenn Sie viele Pakete installiert haben. Wenn Sie dies ausprobieren möchten, können Sie mich gerne um Hilfe bitten.

FWIW, ich habe gerade versucht, eine solche Mega-Autoloads-Datei "von Hand" in meinem Test-Setup zu erstellen. Ergebnisse: Das package-initializeLaden der mega-autoloads.elDatei dauert ungefähr 0,9 Sekunden, das Laden der Datei dauert 0,3 Sekunden, was ich durch Let-Binden load-source-file-functionan Null auf 0,2 Sekunden und durch Byte-Kompilieren der Datei auf 0,1 Sekunden reduzieren kann. Ich habe ehrlich gesagt eine bessere Beschleunigung erwartet, aber es lohnt sich trotzdem.

[BEARBEITEN] Dieser "Mega-Autoloads" -Ansatz ist jetzt in Emacs 'Master-Zweig verfügbar (wird in ferner Zukunft zu Emacs-27). Es wird von der neuen package-quickstartVariablen gesteuert .

Stefan
quelle
Das sind einige sehr interessante Ideen. Die erste klingt bodenständiger und weniger herausfordernd. Der zweite ist ziemlich interessant, aber das klingt nach einem Job für die package.elEntwickler. Was für einen Ratschlag haben Sie, wenn Sie mit dieser ersten Option beginnen? Ich würde gerne sehen, was ich damit machen kann, da es viel praktikabler zu sein scheint.
GDP2
el-get verwendet den Single-Autoloads-Dateiansatz, der im Grunde die meiste Zeit funktioniert. Es gibt Probleme mit einigen Paketen, deren Autoloads vom Speicherort im Dateisystem abhängen, in dem sie ausgewertet werden. Ich verstehe jedoch nicht, was Sie unter "in der richtigen Reihenfolge" verstehen denke, es war sogar deterministisch für aktuelle package.el)?
Npostavs
@ Stefan bitte teile die Lösung hier, wenn möglich.
Manuel Uberti
1
@npostavs: Die meisten <pkg>-autoloads.elDateien richten nur Autoloads ein und kümmern sich in der Tat nicht um die Bestellung, aber nichts hindert sie daran, zufällige andere Dinge zu tun, und package.el garantiert, dass das Paket, von dem es <pkg>abhängt, vor sich <pkg>selbst aktiviert wird .
Stefan
1
Ein weiteres Update zu diesem Thema: Wir haben ein neues Thema auf der Mailingliste beginnen hier und jeder ist frei zu kommentieren oder Test aus Stefans Änderungen.
GDP2
6

Das Problem, das Sie beschreiben, package-initializeweil Sie so viel Zeit zum Laden benötigen, ist ein bekanntes Problem. Es ist auch eines der Probleme, die einige Emacs-Frameworks zu lösen versuchen, indem sie die Autoloads manuell laden.

Ich sehe zwei Lösungen für Ihr Problem.

  1. Schreiben Sie die Funktionalität (oder extrahieren Sie sie aus einem Framework), um die Pfade festzulegen und die Autoloads der Pakete zu laden, an denen Sie interessiert sind.
  2. Verwenden Sie ein Framework, das explizit auf Geschwindigkeit abzielt. Ich persönlich empfehle DOOM Emacs . Mit diesem Framework lade ich mehr als 200 Pakete in ca. 1 Sekunde.

Einer der Hauptgründe für die Empfehlung von DOOM-Emacs ist, dass das Framework die Paketverwaltung außerhalb von Emacs platziert. Verstehen Sie mich nicht falsch, es ist immer noch Emacs, der die Paketverwaltung durchführt. Es ist nur so, dass die Verwaltung von Paketen außerhalb einer Standardbenutzersitzung erfolgt. Die Philosophie hier ist: Wenn wir normalerweise Emacs starten, sollten wir davon ausgehen können, dass alle Pakete vorhanden sind und bereits geladen werden können. Das spart viel Zeit. DOOM Emacs bietet eine Art Äquivalent zu apt-getoder pacmanfür Emacs. Sobald ein Paket installiert ist, wird bei jedem Start von emacs davon ausgegangen, dass es bereits installiert ist. Keine Fragen gefragt.

UndeadKernel
quelle
Puh, ich bin froh zu wissen, dass mich dieses Problem nicht nur betrifft. Vielen Dank, dass Sie mich auf DOOM Emacs aufmerksam gemacht haben. Ich muss es mir genauer ansehen und sehen, was ich an mein eigenes Setup anpassen kann.
GDP2
Ich spiele schon seit einiger Zeit mit DOOM-Emacs (und trage bei, wenn ich kann). Wenn Sie Probleme haben, können Sie mich gerne kontaktieren.
UndeadKernel