Jak mogę poprawić czas uruchamiania pomimo wielu pakietów?

19

TL; DR Mam tak dużą liczbę pakietów, że szkodzi to mojemu uruchomieniu. Jeśli nie uważasz, że może tak być, czytaj dalej.


Czas uruchamiania mojego Emacsa jest dość krótki. Nie używam use-package, po prostu ustawiam mnóstwo haczyków autoload, aby prawie cały kod został odroczony. W rzeczywistości całość jest ładowana zwykle w mniej niż pół sekundy, mimo że wydaje się to szalonym bałaganem.

Jednak z biegiem czasu zauważyłem, że mój czas uruchamiania dostaje drobiazgowo wolniej, w niewytłumaczalny sposób. W końcu doszło do momentu, w którym czas uruchamiania wynosi ≥ 1 sekundę. W końcu miałem dość i sięgnąłem do sedna problemu. W końcu skomentowałem cały ~/.emacsplik i stwierdziłem, że czas uruchamiania wciąż wynosił ≥ 1 sekundę. W rzeczywistości ogolił się ~ 0.2sekund, a czasem nawet krócej. Potem próbowałem emacs -qi okazało się, że czas uruchamiania wynosił ~ 0.1sekund.

Po zbadaniu tej sekcji podręcznika Elisp, dowiedziałem się dlaczego emacs -qzostał skracając czas uruchamiania tyle. Najwyraźniej emacs -qpowstrzymuje Emacsa przed zrobieniem trzech rzeczy podczas uruchamiania:

  1. ładowanie pliku init
  2. ładowanie default.elpliku
  3. powołanie package-initialize

Wykluczyliśmy już mój plik inicjujący, ponieważ skomentowanie mojej całości ~/.emacsprawie nic nie robi. Nie używam default.elpliku, więc jest to również wykluczone. Co pozostawia package-initializewinowajcę za hit.

Dlaczego package-initializezabiera tyle czasu na uruchomienie? To było pierwsze pytanie, które sobie zadałem. Czy nie ładuję wszystkiego automatycznie? No tak. Ale to jest właśnie problem.

Znalazłem ten post, który wyjaśnia, że ​​„aktywowanie” pakietów polega na odczytywaniu plików autoload i ustawianiu ścieżek ładowania. To oczywiście powoduje karę we / wy, gdy masz wiele pakietów, ponieważ masz wiele plików autoload do odczytu i wiele ścieżek do ustawienia. Niestety bez tego zadanie zarządzania automatycznymi ładowaniami spada na użytkownika. Innymi słowy, nie pozwalając na package.elindeksowanie systemu plików w celu automatycznego ładowania plików i ścieżek, musiałbym sam sobie z tym poradzić, co może być żmudnym i podatnym na błędy procesem.

Wolałbym nie iść tą drogą. Obecnie mam 116 pakietów, w tym 107 z ELPA, z czego 25 to zależności. Jestem pewien, że ta ogromna liczba tak bardzo obniża moją wydajność. Ale jestem w rozterce, ponieważ nie chcę usuwać żadnego z moich pakietów.

Czy w takiej sytuacji jest jakiś sposób na odzyskanie czasu uruchamiania błyskawicy?


Aktualizacja:

Rozpoczęliśmy nowy wątek na emacs-develliście mailowej o niektórych łatach autorstwa Stefana Monniera (opis tych łatek jest tutaj ), aby rozwiązać ten problem. Każdy może przetestować swoje łatki i wyrazić opinię.

Kolejna aktualizacja:

Wygląda na to, że Stefan Monnier albo nie jest już zainteresowany tym problemem, albo nie otrzymuje moich wiadomości. Jestem skłonny wierzyć w to pierwsze, co jest w porządku, chociaż byłbym wdzięczny za jakąś odpowiedź od niego, jeśli tak jest. Zresztą kod, który do tej pory stworzył dla tego problemu, działa całkiem dobrze. Najnowsze jego łaty można znaleźć tutaj (dla Emacsa 25.3) i tutaj (dla głównej gałęzi Emacsa).Zauważyłem dobre ulepszenia czasu uruchamiania dzięki jego łatkom i jestem w punkcie, w którym czuję się dobrze z czasem uruchamiania, o ile jest on zoptymalizowany tak, jak to możliwe, bez wyłączania funkcji mojego dostosowania. Miałem nadzieję, że te łaty w pewnym momencie znajdą się na linii głównej Emacsa, ale chyba (lub ktoś inny) musiałbym teraz zająć się pochodnią, zamiast Stefana. Mieliśmy trochę uwagi na liście mailingowej dotyczącej przypisywania praw autorskich i licencjonowania. Początkowo nie czułem się z tym dobrze, ale z powodu niektórych komentarzy Richarda Stallmana i innych, przypisanie praw autorskich może nie być tak restrykcyjne, jak początkowo myślałem. Ponadto może być możliwe przekazanie moich dzieł do domeny publicznej jako alternatywa dla przypisania praw autorskich.

W każdym razie dziękuję Stefanowi za dotychczasowe łaty! Mam nadzieję, że nadal będziecie rozwijać te zmiany, ale jeśli nie, to w porządku i mogę je w dalszym ciągu rozwijać. Dziękuję również wszystkim innym, którzy zaoferowali wgląd i wkład w rozwiązanie tego problemu.

Kolejna aktualizacja:

Wow, wygląda na to, że ta funkcja w końcu wylądowała i będzie w Emacs 27. Dzięki Stefan Monnier!

PKB2
źródło
Świetne pytanie.
Drew
use-packagejest na to sposób.
Dodgie
Nie próbuj bagatelizować problemu (ważne jest opóźnienie uruchamiania!), Ale rozważ uruchomienie emacsa jako demona / serwera, aby płacić tylko za uruchomienie.
GManNickG
1
@GManNickG Uruchomiłem Emacsa jako serwer. Niestety, od czasu do czasu naciskam Emacsa zbyt mocno lub majstruje przy nim zbyt mocno, a ponowne uruchomienie jest najlepszym sposobem na oczyszczenie. Kiedy tak się dzieje, podoba mi się optymalny czas uruchamiania.
GDP2

Odpowiedzi:

13

Jedną z opcji projektowania w pakiecie.el była próba uczynienia rzeczy „prostymi”. Częścią tego jest to, że package-initializewyszukuje wszystkie zainstalowane pakiety, a następnie próbuje dowiedzieć się, które z nich powinny zostać aktywowane (zgodnie z przypinaniem i ponownością wersji w przypadku, gdy dostępnych jest wiele wersji tego samego pakietu), a następnie ładuje każdy <pkg>-autoloads.elplik pakietu aktywuje .

Tak więc dla N zainstalowanych pakietów, oznacza to w zasadzie czytanie N <pkg>-pkg.elplików opisu pakietów i N <pkg>-autoloads.elplików. W przypadku dużych N może to stać się poważnym problemem. Innym potencjalnym problemem związanym z wydajnością jest to, że doda N elementów load-path, więc za każdym razem, gdy loadEmacs będzie przeszukiwał N katalogów, każdy z nich loadzostanie spowolniony.

Istnieją różne sposoby przyspieszenia tego:

  • Podaj sposób na wstępne obliczenie ~/.emacs.d/elpa/package-initialize.el(c)pliku, który byłby wynikiem połączenia wszystkich właściwych elementów <pkg>-autoloads.elwe właściwej kolejności. Następnie package-initializemoże po prostu załadować ten plik, gdy jest obecny i pominąć wszystko inne. Będziesz wtedy potrzebować sposobu na odświeżenie / opróżnienie package-initialize.el(c)pliku, gdy pakiety zostaną dodane / zaktualizowane / usunięte lub gdy zmienisz swój package-pinned-packageslub własny package-load-list. Myślę, że można tego dokonać przy niewielkiej liczbie zmian w systemie (jedyne, co naprawdę wymagałoby zmiany, myślę package-initialize, że można powiedzieć, aby „aktywowała się tylko” bez ładowania metadanych o dostępnych pakietach).

  • Zapewnij sposób na budowanie / manipulowanie super-pakietami, tj. Pakiet, który łączy kilka pakietów w jeden (więc jest dodany tylko jeden element load-path, jeden <pkg>-pkg.eli jeden <pkg>-autoloads.elzaładowany). Może to być trudniejsze (ponieważ wtedy nie można aktywować tylko części pakietów zawartych w takich super-pakietach, więc analiza zależności / wersji może być trudna).

Pierwsza powyższa opcja powinna być dość łatwa do wdrożenia i package-initialize znacznie przyspieszyłaby, gdy zainstalowano wiele pakietów. Jeśli chcesz to wypróbować, możesz poprosić mnie o pomoc.

FWIW, właśnie próbowałem zbudować taki plik mega-autoloads „ręcznie” na mojej konfiguracji testowej. Wyniki: podczas gdy package-initializetrwa około 0,9 s, ładowanie mega-autoloads.elpliku zajmuje 0,3 s, co mogę obniżyć do 0,2 s przez powiązanie let load-source-file-functiondo zera i do 0,1 s przez kompilację bajtów pliku. Szczerze mówiąc, spodziewałem się lepszego przyspieszenia, ale nadal warto.

[EDYCJA] To podejście „mega autoloads” jest teraz dostępne w głównej gałęzi Emacsa (aby stać się Emacs-27 w odległej przyszłości). Jest kontrolowany przez nową package-quickstartzmienną.

Stefan
źródło
To są bardzo ciekawe pomysły. Pierwszy brzmi bardziej przyziemnie i nie stanowi większego wyzwania. Drugi jest dość interesujący, ale brzmi to jak praca dla package.elprogramistów. Jaką masz radę, rozpoczynając od pierwszej opcji? Chciałbym zobaczyć, co mogę z tym zrobić, ponieważ wydaje się to o wiele bardziej wykonalne.
GDP2
el-get używa pojedynczego pliku autoloads, działa w zasadzie przez większość czasu. Występują problemy z niektórymi pakietami, których automatyczne ładowanie zależy od lokalizacji w systemie plików, w którym są one oceniane. Nie rozumiem jednak, co masz na myśli, mówiąc „we właściwej kolejności”, dlaczego kolejność automatycznego ładowania zawsze miałaby znaczenie (ja nie myślisz, że to było nawet deterministyczne dla obecnego pakietu. el)?
npostavs
@Stefan, jeśli to możliwe, udostępnij rozwiązanie tutaj.
Manuel Uberti
1
@npostavs: Większość <pkg>-autoloads.elplików konfiguruje tylko automatyczne ładowanie i rzeczywiście nie przejmuje się zamawianiem, ale nic nie stoi na przeszkodzie, aby robiły losowe inne rzeczy, a package.el gwarantuje, że pakiet, od którego <pkg>zależy, zostanie aktywowany przed <pkg>sobą.
Stefan
1
Kolejna aktualizacja na ten temat: rozpoczęliśmy nowy temat na liście mailingowej tutaj i każdy może komentować lub testować zmiany Stefana.
GDP2
6

Problem, package-initializektóry opisujesz poświęcając tyle czasu na załadowanie, jest dobrze znanym problemem. Jest to również jeden z problemów, które niektóre frameworki emacsa próbują rozwiązać, ręcznie ładując autoloady.

Widzę dwa rozwiązania twojego problemu.

  1. Napisz (lub wypakuj z frameworka) funkcjonalność, aby ustawić ścieżki i załadować automatyczne ładowanie pakietów, którymi jesteś zainteresowany.
  2. Użyj frameworku, który wyraźnie określa prędkość. Osobiście polecam DOOM emacs . Dzięki tej ramie ładuję ponad 200 pakietów w około 1 sekundę.

Jednym z głównych powodów rekomendacji emacsa DOOM jest to, że środowisko zarządzania pakietami poza emacsem. Nie interpretuj mnie źle, nadal emacs zajmuje się zarządzaniem pakietami, po prostu zarządzanie pakietami odbywa się poza standardową sesją użytkownika. Oto filozofia: kiedy normalnie uruchamiasz emacsa, powinniśmy być w stanie założyć, że wszystkie pakiety są obecne i można je już załadować. To oszczędza dużo czasu. DOOM emacs zapewnia swego rodzaju odpowiednik apt-getlub pacmanemacs. Po zainstalowaniu pakietu, przy każdym uruchomieniu emacsa zakłada się, że jest już zainstalowany; brak pytań.

UndeadKernel
źródło
Uff, cieszę się, że ten problem dotyczy mnie nie tylko. Dziękujemy za skierowanie mnie do DOOM Emacs. Będę musiał przyjrzeć się temu bliżej i zobaczyć, co mogę dostosować do własnej konfiguracji.
GDP2
Od jakiegoś czasu bawię się z emacami DOOM (i pomagam, kiedy mogę). Jeśli masz problemy, skontaktuj się ze mną.
UndeadKernel