Wie verhindere ich, dass extrem lange Zeilen den Emacs langsam machen?


72

Ich sehe eine sehr unterschiedliche Leistung, abhängig davon, wie viele Zeilen in der Datei sind, die ich besuche.

Hier ist ein Beispiel. Ich habe zwei JSON-Dateien:

$ wget https://github.com/Wilfred/ReVo-utilities/blob/a4bdc40dd2656c496defc461fc19c403c8306d9f/revo-export/dictionary.json?raw=true -O one_line.json
$ python -m json.tool <one_line.json >pretty_printed.json

Dies sind zwei JSON-Dateien mit demselben Inhalt. one_line.jsonist 18 MB JSON ohne Zeilenumbruch. pretty_printed.jsonNewlines und Whitespace hinzugefügt, so dass es 41MiB.

Die über viele Zeilen verteilte größere Datei lässt sich jedoch in Emacs sowohl im JavaScript-Modus als auch im Fundamental-Modus viel schneller öffnen.

Warum hat Emacs bei langen Leitungen eine so schlechte Leistung, weil es eigentlich weniger Bytes sind? Kann ich die Leistung verbessern, ohne die Daten außerhalb von Emacs neu zu formatieren?


2
Nicht wirklich eine Antwort , aber vielleicht von Nutzen sein: View Large Files(VLF) ist ein kleiner Betrieb , das Ziel, mit der Bearbeitung von großen Dateien zu helfen , indem sie beim Laden Chargen . Haftungsausschluss: Ich habe es nie benutzt und ich weiß nicht, ob es auch lange Zeilen in Stapeln verarbeitet .
Elemakil

3
Wenn ich diese Art von Verhalten kenne und mich vor allem davor hüte, ein Protokoll zu lesen, das eine lange Reihe ausspuckt, mache ich oft etwas wie $ tail -f /some/file | fold -sin einem Shell-Puffer. Das ist natürlich nicht gut zum Bearbeiten, hilft aber beim Lesen.
wvxvw

Antworten:


50

Emacs 'Umgang mit langen Schlangen ist nicht sehr gut optimiert. Für eine Reihe von Operationen muss Emacs die gesamte Zeile wiederholt scannen. Um beispielsweise eine Linie anzuzeigen, muss Emacs die Höhe der Linie ermitteln. Dazu muss die gesamte Linie gescannt werden, um die höchste Glyphe zu finden. Darüber hinaus nimmt das Scannen nach bidirektionaler Anzeige viel Zeit in Anspruch. Sie können einige zusätzliche Informationen erhalten, z. B. in der Dokumentzeichenfolge von cache-long-line-scans( cache-long-scansin 24.4 umbenannt ).

Sie können versuchen und sehen , ob Einstellung bidi-paragraph-directionauf left-to-rightdie Geschwindigkeit für Sie verbessert [Einstellung bidi-display-reorderingzu nil, tut mehr oder weniger das gleiche , sondern nur für den internen / Debug - Zwecke gedacht]. Dies entfernt einen signifikanten Beitrag zu Linienscans, aber leider nicht den einzigen.

Die beste Option ist das Hinzufügen von Zeilenumbrüchen. Sie können eine JSON-Datei python -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'weiterleiten, um z. B. neue Zeilen hinzuzufügen und die Lesbarkeit zu verbessern.


4
Kann man das aus Neugier nicht algorithmisch verbessern?
PythonNut

9
Bei der Auswahl der zugrunde liegenden Datenstruktur eines Editors müssen Sie zwischen bestimmten Vor- und Nachteilen wählen. Emacs verwendet einen Lückenpuffer , der eine äußerst platzsparende Datenstruktur zum Einfügen und Löschen darstellt, aber zeilenbasierte Vorgänge verlangsamt, da Sie nacheinander nach einer neuen Zeile suchen müssen. Emacs könnte eine andere Datenstruktur verwenden, aber das würde andere Vorgänge verlangsamen. Emacs verwendet bereits einen Zeilen-Cache, aber das hilft nicht in allen Situationen. Algorithmisch nicht einfach zu verbessern, aber Profilerstellung und Optimierung schaden nie. :-)
Jorgen Schäfer

4
(setq-default bidi-display-reordering nil)- Einige Benutzer erkennen möglicherweise nicht, dass es sich um eine pufferlokale Variable handelt, für die möglicherweise eine Standardeinstellung erforderlich ist, sofern ein Benutzer dies als global wünscht. Ich wünschte, ich hätte das vor Jahren hinzugefügt init.el... aber zumindest ist es jetzt da. Vielen Dank !!!
Gesetzesliste

In meinem Fall war es kein großes Improvent (wirklich lange JSON-Zeilen mit Base64-Dokumenten-Body), aber es hilft viel beim Beign Freezing
Anquegi

1
Der aktuelle Emacs-Betreuer, Eli, der den BIDI-Code geschrieben hat, schreibt über das Ausschalten bidi-display-reordering: "Ein Kommentar, den ich habe, ist, dass das Deaktivieren der Bidi-Anzeige-Neuordnung ... die Anzeige-Engine in einen Zustand versetzt, der nicht getestet wird, und Inkonsistenzen verursachen kann und sogar Fehler (weil einige Teile des Codes unter der Annahme geschrieben wurden, dass diese Variable niemals Null ist). "
Clément

18

Ich habe einige kurze Experimente mit einer verkleinerten Kopie von jquery durchgeführt. font-lock-modeund flycheck-modebeide trugen zur Langsamkeit, wie tat js2-mode, und prettify-symbols-mode. line-number-modeund column-number-modehatte geringe Wirkung. Einmal hatte ich die verschiedenen Modi ausgeschaltet, obwohl die Leistung relativ bissig war. Verwenden C-h mund deaktivieren Sie verschiedene aktivierte Modi, oder wechseln Sie einfach zu fundamental-mode.

Interessanterweise hexl-modekonnte ich die Datei ohne Probleme durchfliegen, obwohl die Spalten offensichtlich ziemlich kurz waren. Leider visual-line-modesehr verlangsamt.

Ich vermute, dass die Syntaxtabelle die Verarbeitung gerne an den Zeilenenden unterbricht, und wenn alles in einer Zeile steht, muss sie bei jedem Update alles neu analysieren.


2
Können Sie einen Fehlerbericht in Flychecks Tracker öffnen? Ich bin mir ziemlich sicher, dass wir keine langen Schlangen wollen, die Probleme verursachen, und Emacs + Flycheck sollten nicht schlechter sein als Emacs (was immer noch ziemlich schlecht ist).
Clément

16

Ich habe http://www.emacswiki.org/emacs/OverLongLineMode hochgeladen

Mit dieser Bibliothek können Sie einfache Schwellenwerte für die Zeilenlänge festlegen, ab denen fundamental-modeanstelle des normalen Modus eine Variante von für eine Datei verwendet wird (nur für Programmiermodi).

Möglicherweise könnte Emacs standardmäßig etwas in diese Richtung hinzugefügt werden. Dies kann jedoch eine vorläufige Lösung für das Hauptproblem sein, dass Emacs beim Auffinden einer solchen Datei langsamer kriecht.

nb Dies ist eine Verbesserung gegenüber dem Code, den ich ursprünglich in dieser Antwort gepostet habe, aber immer noch in Arbeit. Das Testen war minimal. Kommentare sind willkommen.

Vorschläge für andere (außer css-mode) nicht- prog-modeabgeleitete Hauptmodi, die standardmäßig unterstützt werden, werden ebenfalls begrüßt.


1
Jetzt weiter verbessert und beschämend in so-long.el :) umbenannt (der obige Link wird umleiten). Es gibt noch mehr, was man damit machen könnte, aber es ist zu 100% funktional und nützlich wie es ist.
Phils

Dies ist eine wirklich schöne Lösung (würde es gerne auf MELPA sehen), aber meine Emacs-Instanz ist beim Öffnen von one_line.json immer noch extrem langsam. Ich denke, es wäre deutlich schneller, wenn es nicht zuerst den Hauptmodus aktiviert hätte.
Wilfred Hughes

3
Nach dem erneuten Lesen und Verwenden Ihrer one_line.json-Datei aus der Frage habe ich das Warten auf die Standardkonfiguration von Emacs 25.3 und 26.0.91 aufgegeben, nachdem ich sie gebeten hatte, diese Datei zu öffnen (nachdem ich mehr als eine Minute gewartet hatte), während meine eigene config mit so-long.elactive öffnete die datei in weniger als 2 sekunden. Das eigentliche Bearbeiten der Datei ist immer noch äußerst problematisch (z. B. der Versuch, in die nächste Zeile zu wechseln, wird extrem lange dauern), aber dennoch wird mein Vertrauen in die Nützlichkeit der von mir geschriebenen Bibliothek wiederhergestellt, sodass ich meine Pläne wieder aufnehmen sollte füge es zu GNU ELPA hinzu ...
phils

1
Ist es schon in (M) ELPA?
Binki

3
Statusbericht: Version 1.0 von so-long.el(mit zahlreichen Verbesserungen) ist in den aktuellen Entwicklungsversionen von Emacs 27 enthalten und wird in naher Zukunft (für frühere Versionen von Emacs) über GNU ELPA verfügbar sein.
Phils

7

Ich nehme an, Sie werden feststellen, dass der Unterschied darauf zurückzuführen ist font-lock. Wenn die Schrift an der im Fenster sichtbaren Teilmenge der Datei vorgenommen werden soll, wird zunächst der Schriftbereich so erweitert, dass er vollständige semantische Einheiten enthält. Siehe dazu den font-lock-extend-region-functionsCode. Es ist üblich, die Region auf vollständige Zeilen zu erweitern. Wenn die Zeilen extrem lang sind, kann dies dazu führen, dass die Fontifizierung über einen sehr viel größeren Teil des Inhalts ausgeführt wird, als tatsächlich sichtbar ist.

Wenn Zeilenumbrüche selbst semantische Informationen enthalten, kann ihre Abwesenheit manchmal dazu führen, dass reguläre Ausdrücke für die Schriftsperre weiter gescannt werden müssen, um festzustellen, ob sie übereinstimmen oder nicht.


7

Normalerweise löse ich lange Zeilen auf und rücke nach Tags ein (wie HTML, XML, JSON).

Um eine solche Operation zu ermöglichen, füge ich hinzu:

(setq line-number-display-limit large-file-warning-threshold)
(setq line-number-display-limit-width 200)

(defun my--is-file-large ()
  "If buffer too large and my cause performance issue."
  (< large-file-warning-threshold (buffer-size)))

(define-derived-mode my-large-file-mode fundamental-mode "LargeFile"
  "Fixes performance issues in Emacs for large files."
  ;; (setq buffer-read-only t)
  (setq bidi-display-reordering nil)
  (jit-lock-mode nil)
  (buffer-disable-undo)
  (set (make-variable-buffer-local 'global-hl-line-mode) nil)
  (set (make-variable-buffer-local 'line-number-mode) nil)
  (set (make-variable-buffer-local 'column-number-mode) nil) )

(add-to-list 'magic-mode-alist (cons #'my--is-file-large #'my-large-file-mode))

I gespalten Linie durch regex, für XML es: C-M-% >< RET >NL< RET !.

Nachdem Emacs lange Zeilen geteilt hat, können Sie viele *-modesCodes aktivieren und neu einrücken.

Zum Hinweis: Wie kann eine Verlangsamung verhindert werden, wenn ein minderwertiger Prozess lange Schlangen erzeugt?


4

Ich habe hier meine eigene Lösung für dieses Problem erstellt: https://github.com/rakete/too-long-lines-mode

Ich war nicht zufrieden mit der phils-Lösung, die einen Puffer mit sehr langen Zeilen in den Fundamental-Modus versetzt. Ich wollte eine Lösung, mit der ich Syntax-Hervorhebungen und andere Hauptfeatures des Modus beibehalten kann. Deshalb habe ich einen Nebenmodus erstellt, der Überlagerungen verwendet, um die meisten Zeichen übermäßig langer Zeilen auszublenden.

Das umgeht das Problem und macht den Emacs auch in Puffern mit sehr langen Zeilen einsetzbar, ohne auf den Fundamental-Modus zurückgreifen zu müssen.


2

In meinem Emacs-Setup habe ich einen Modus mit benutzerdefinierter Schriftart, dh wo ich festgelegt habe font-lock-defaults. Eine einzelne Seite nach unten würde 30 Sekunden benötigen, um einen Teil der 30000-Zeichenzeile anzuzeigen. Diese Verlangsamung wurde behoben, indem das Regexp-Backtracking reduziert wurde. Anstatt von:

  (". * endete mit einem unvollständigen Befehl *" 0 font-lock-comment-face)

mach das

  ("^. \ {1,80 \} endete mit einem unvollständigen Befehl *" 0 font-lock-comment-face)

Dies ist keine Antwort auf die Frage, bei der es nicht speziell um font-lock-defaultsoder Regexp-Übereinstimmung geht.
Drew

1
@Drew Weniger als ideal regex ist zu machen ... wenn auf langen Leitungen langsam font-lock
wasamasa

1
@wasamasa: Ja. Die Frage selbst ist zu weit gefasst, IMO. Es gibt viele Dinge, die Emacs verlangsamen können (und für welche Aktionen?), Wenn lange Schlangen involviert sind.
Drew

3
Ich denke nicht, dass die Frage zu breit ist ("warum machen lange Schlangen Emacs langsam")? Ich denke auch nicht, dass die Antwort die Frage nicht beantwortet (" ein möglicher Grund sind suboptimale reguläre Ausdrücke"). Andere Antworten können andere Gründe ansprechen. Das Öffnen einer Datei mit langen Zeilen ist nicht zu umfangreich, nur weil dies aus verschiedenen Gründen problematisch sein kann. Manchmal haben Sie solche Dateien und müssen sie anschauen, vorzugsweise mit Emacs.
Tarsius

1

In meinen Shell-Mode-Puffern (Mx-Shell) muss ich Pipes verwenden sed -r 's/(.{2000}).*/\1/' -u, um lange Zeilen zu vermeiden.


Dies beantwortet den zweiten Teil der Frage: Wie kann die Leistung verbessert werden? Der erste Teil (der in Ordnung ist) wird nicht angesprochen: " Warum hat der Emacs bei langen Warteschlangen eine so schlechte Leistung ?"
Drew

0

Ich benutze die folgende Funktion zum Öffnen in dired-modegroßen Dateien mit langen Zeilen:

(defun dired-find-file-conservatively ()
   (interactive)
   (let ((auto-mode-alist nil))
     (dired-find-file)
     ;; disable costly modes
     (fundamental-mode)
     (setq-local bidi-display-reordering nil)
     (when (boundp 'smartparens-mode)
       (smartparens-mode -1))))

(define-key dired-mode-map (kbd "S-<return>") 'dired-find-file-conservatively)

0

Hier ist eine Problemumgehung aus Emacs-Devel :

(add-hook 'find-file-hook
          (defun my-find-file-care-about-long-lines ()
            (save-excursion
              (goto-char (point-min))
              (when (and (not (eq major-mode 'image-mode))
                         (search-forward-regexp ".\\{2000\\}" 50000 t)
                         (y-or-n-p "Very long lines detected - enable 
longlines-mode? "))
                (require 'longlines)
                (longlines-mode +1)))))

In Emacs ab 24.4 wurde der longlines-modeals überholt markiert visual-line-mode.
Alexander I.Grafov

Hinter den Kulissen machen die beiden Funktionen jedoch sehr unterschiedliche Dinge und visual-line-modehelfen nicht bei dem fraglichen Problem, wohingegen dies der longlines-modeFall ist. Aus diesem Grund erwarte ich, dass longlines.el auf einen nicht veralteten Status zurückgesetzt wird.
Phils
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.