非常に長い行がEmacsを遅くするのを防ぐにはどうすればよいですか?


72

訪問しているファイルに含まれる改行の数によって、パフォーマンスが大きく異なります。

以下に例を示します。2つのJSONファイルがあります。

$ 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

これらは、同じコンテンツを持つ2つのJSONファイルです。one_line.json改行なしの18MiBのJSONです。pretty_printed.json改行と空白が追加され、41MiBになりました。

ただし、多くの行に分割された大きなファイルは、JavascriptモードとFundamentalモードの両方で、Emacsで開く方がはるかに高速です。

Emacsは実際にはバイト数が少ないので、長い行でパフォーマンスが低下するのはなぜですか?Emacsの外部でデータを再フォーマットせずにパフォーマンスを改善するためにできることはありますか?


2
本当の答えではありませんが、役に立つかもしれません:View Large Files(vlf)は大きなファイルをバッチでロードすることで編集するのを助けることを目的としたマイナーモードです。免責事項:一度も使用したことはなく、長い行をバッチで処理するかどうかもわかりません。
エレマキル14年

3
この種の振る舞いを知っており、特に長い行を吐き出すログを読み取らないようにしようとするとき$ tail -f /some/file | fold -sは、シェルバッファーで何かをすることがよくあります。これは明らかに編集には適していませんが、読書には大いに役立ちます。
wvxvw 14

回答:


50

Emacsの長い行の処理はあまり最適化されていません。多くの操作では、Emacsは行全体を繰り返しスキャンする必要があります。たとえば、行を表示するには、Emacsは行の高さを把握する必要があり、行全体をスキャンして最も高いグリフを見つける必要があります。さらに、双方向ディスプレイのスキャンには時間がかかります。たとえば、docstring cache-long-line-scanscache-long-scans24.4で名前変更)で追加情報を取得できます。

に設定すると速度bidi-paragraph-directionleft-to-right向上するかどうかを確認できます[に設定bidi-display-reorderingするnilと、ほぼ同じになりますが、内部/デバッグのみを目的としています]。これにより、ラインスキャンへの重要な貢献者が1人削除されますが、悲しいことに1人だけではありません。

最適なオプションは、改行を追加することです。JSONファイルをパイプ処理して、たとえばpython -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'改行を追加し、一般的に読みやすさを向上させることができます。


4
好奇心から、これはアルゴリズム的に改善できないものですか?
PythonNut

9
エディターの基礎となるデータ構造を選択する場合、特定の長所と短所を選択する必要があります。Emacsは挿入と削除のためのスペース効率の高いデータ構造であるギャップバッファーを使用しますが、改行を順番にスキャンする必要があるため、行ベースの操作が遅くなります。Emacsは別のデータ構造を使用できますが、それにより他の操作が遅くなります。Emacsはすでにラインキャッシュを使用していますが、それはすべての状況で実際に役立つわけではありません。そのため、アルゴリズム的に簡単に改善することはできませんが、プロファイリングと最適化が損なわれることはありません。:-)
ヨルゲンシェーファー

4
(setq-default bidi-display-reordering nil)-一部のユーザーは、これがバッファーローカル変数であることを認識していない可能性があります。ユーザーがこれをグローバルにしたい場合、デフォルト設定が必要になる場合があります。私はinit.el何年も前にそれを追加したかったのですが...少なくとも今はそこにあります。どうもありがとうございました!!!
法律家

私の場合、それは大きなimproventませんでした(BASE64文書本体と本当に長いJSON線)が、beign凍結に多くのことができます
anquegi

1
BIDIコードを書いた現在のEmacsメンテナーであるEliは、スイッチを切ることについて次のように書いていbidi-display-reorderingます。バグさえあります(コードの一部は、この変数が決してnilでないという仮定の下で書かれたためです)。
クレマン

18

jqueryの縮小コピーを使用して、これについていくつか簡単な実験を行いました。font-lock-modeそして、flycheck-mode両方が遅さの一因js2-modeとなりましたprettify-symbols-modeline-number-modeそして、column-number-modeわずかな影響がありました。パフォーマンスは比較的きびきびでしたが、さまざまなモードをすべてオフにすると、C-h m有効になっているさまざまなモードを使用して無効にするか、単にに切り替えてみてくださいfundamental-mode

興味深いことに、hexl-mode私は問題なくファイルを飛ぶことができましたが、明らかに列は非常に短いものでした。残念なことに、visual-line-mode事態は本当に遅くなりました。

私の推測では、構文テーブルは行末で処理を停止し、すべてが1行になった場合は、更新のたびにすべてを再解析する必要があります。


2
Flycheckのトラッカーでバグレポートを開くことはできますか?長い行が問題を引き起こすことを望んでいないことは確かであり、Emacs + FlycheckはEmacs(それでもかなり悪い)より悪くないはずです。
クレメント

16

http://www.emacswiki.org/emacs/OverLongLineModeをアップロードしました

このライブラリを使用すると、単純な行長のしきい値を設定できます。これを超えるとfundamental-mode、ファイルの通常モードの代わりにのバリアントが使用されます(プログラミングモードのみ)。

これらの行に沿ったものがデフォルトでEmacsに追加される可能性がありますが、これはEmacsがそのようなファイルに遭遇したときにクロールが遅くなるという主要な問題に対する暫定的な回避策です。

nbこれは、この回答で最初に投稿したコードの改善ですが、まだ進行中の作業です。テストは最小限に抑えられています。コメントを歓迎します。

デフォルトでサポートする他の(以外のcss-mode)非prog-mode派生メジャーモードの提案も歓迎します。


1
さらに改善され、残念ながらso-long.elに名前が変更されました:)(上記のリンクはリダイレクトされます)。これでできることは他にもありますが、100%機能的で便利なものです。
phils

これは本当に素晴らしい解決策です(MELPAで見たいと思います)が、one_line.jsonを開くとき、私のEmacsインスタンスはまだ非常に遅いです。最初に元のメジャーモードをアクティブにしないと、大幅に高速になると思います。
ウィルフレッドヒューズ

3
これを読み直し、質問のone_line.jsonファイルを使用して、default-config Emacs 25.3および26.0.91がそのファイルを開くように要求した後(1分以上待った後)応答するのをgaveめました。 config with so-long.elactiveは、ファイルを2秒以内に開きました。実際、ファイルの編集には依然として大きな問題があります(たとえば、「次の行」に移動しようとすると非常に長い時間がかかります)が、それでも、作成したライブラリの有用性に対する信頼が回復するので、計画を再開する必要がありますGNU ELPAに追加します...
phils

1
まだ(M)ELPAですか?
ビンキ

3
ステータスレポート:(so-long.el多数の機能強化を含む)バージョン1.0は、Emacs 27の現在の開発バージョンに含まれており、近いうちにGNU ELPAを介して(以前のバージョンのEmacsで)利用可能になります。
フィルス

7

違いが原因であることがわかると思いますfont-lock。ウィンドウに表示されているファイルのサブセットでフォント化を実行する場合、最初にフォント化領域を拡張して、完全な意味単位を含むようにします。font-lock-extend-region-functionsこのコードを参照してください。これには、リージョンを拡張して全行を含めることが一般的です。行が非常に長い場合、実際に表示されるよりもはるかに大きなコンテンツのチャンクでフォント化が実行される可能性があります。

さらに、改行自体にセマンティック情報がある場合、それらの不在は、フォントロックの正規表現パターンが一致するかどうかを判断するためにさらにスキャンする必要があることを意味する場合があります。


7

通常、長い行を展開し、タグ(HTML、XML、JSONなど)でインデントします。

このような操作を可能にするために、次を追加します。

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

XMLの場合、正規表現で行を分割しますC-M-% >< RET >NL< RET !

Emacsが長い行を分割した後-多くの*-modesコードを有効にしてインデントを再設定することが可能です。

注:劣ったプロセスが長い行を生成するときの速度低下を防ぐ方法は?


4

この問題に対する独自のソリューションをここで作成しました:https : //github.com/rakete/too-long-lines-mode

非常に長い行のバッファーを基本モードに切り替えるphilsソリューションには満足できませんでした。構文の強調表示やその他の主要なモード機能を維持できるソリューションが必要でした。そこで、オーバーレイを使用して、長すぎる行のほとんどの文字を隠すマイナーモードを作成しました。

これは問題を回避し、基本モードにフォールバックすることなく、非常に長い行を持つバッファーでもemacsを使用可能にします。


2

Emacsのセットアップには、カスタムフォント化、つまり設定するモードがありますfont-lock-defaults。1ページ下に30秒を使用して、30000文字行の一部を表示します。このスローダウンは、正規表現のバックトラッキングを減らすことで修正されました。の代わりに:

  ( "。*は不完全なコマンドで終了しました*" 0 font-lock-comment-face)

これを行う

  ( "^。\ {1,80 \}は不完全なコマンドで終了しました*" 0 font-lock-comment-face)

これは質問への答えではなく、具体的にはfont-lock-defaults正規表現マッチングではありません。
ドリュー

1
@Drew理想的でない正規表現長い行でフォントロックを遅くしています
...-wasamasa

1
@wasamasa:はい。質問自体は広すぎます、IMO。長い行が関係している場合、Emacsを遅くする可能性のあるものがたくさんあります(そして、どのアクションのために?)。
ドリュー

3
私は、質問が広範であるとは思わない(「なぜ長い行がEmacsを遅くするのか」)?また、答えが質問に対応していないとは思わない(「考えられる理由の1つは準最適な正規表現」)。他の答えは、他の理由に対処できます。長い行を持つファイルを開くことは、さまざまな理由で問題になる可能性があるという理由だけでトピックを広めることではありません。
タルシウス

1

シェルモードバッファー(Mxシェル)では、sed -r 's/(.{2000}).*/\1/' -u長い行を避けるためにパイプを使用しています。


これは、質問の2番目の部分、つまりパフォーマンスを改善する方法に答えます。最初の部分(これは問題ありません)については説明していません。
ドリュー

0

dired-mode長い行の大きなファイルを開くには、次の関数を使用します。

(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

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

24.4の時点のEmacsでは、はlonglines-modeによって廃止されたものとしてマークされましたvisual-line-mode
アレクサンダーI.グラフォフ

ただし、この2つの機能は舞台裏で非常に異なることvisual-line-modeを行い、問題の問題を解決するのに役立ちませんlonglines-mode。このため、longlines.elは非推奨ステータスに復元されると予想しています。
phils
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.