Bagaimana cara mencegah garis yang sangat panjang membuat Emacs lambat?

72

Saya melihat kinerja sangat bervariasi tergantung pada berapa banyak baris baru di file yang saya kunjungi.

Ini sebuah contoh. Saya punya dua file 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

Ini adalah dua file JSON dengan konten yang sama. one_line.jsonadalah 18MiB dari JSON tanpa baris baru. pretty_printed.jsonmemiliki baris baru dan spasi putih ditambahkan, menjadikannya 41MiB.

Namun, pemisahan file yang lebih besar pada banyak baris jauh lebih cepat untuk dibuka di Emacs, baik dalam mode Javascript dan mode Fundamental.

Mengapa Emacs memiliki kinerja yang buruk dengan garis yang panjang, karena itu sebenarnya lebih sedikit byte? Adakah yang bisa saya lakukan untuk meningkatkan kinerja tanpa memformat ulang data di luar Emacs?

Wilfred Hughes
sumber
2
Tidak benar-benar jawaban tetapi mungkin berguna: View Large Files(vlf) adalah mode minor yang bertujuan untuk membantu mengedit file besar dengan memuatnya dalam batch . Disclaimer: Saya tidak pernah pakai itu dan saya tidak tahu apakah itu menangani antrean panjang di batch juga.
elemakil
3
Mengetahui perilaku semacam ini, dan terutama ketika mencoba untuk menjaga diri saya dari membaca log yang meludahkan garis panjang, saya sering melakukan sesuatu seperti $ tail -f /some/file | fold -sdi buffer shell. Jelas ini tidak baik untuk diedit, tetapi banyak membantu dalam membaca.
wvxvw

Jawaban:

50

Penanganan garis panjang Emacs tidak dioptimalkan dengan baik. Untuk sejumlah operasi, Emacs harus memindai seluruh baris berulang kali. Misalnya, untuk menampilkan garis, Emacs harus mencari tahu ketinggian garis, yang mengharuskan pemindaian seluruh garis untuk menemukan mesin terbang tertinggi. Selain itu, pemindaian untuk tampilan dua arah memakan banyak waktu. Anda bisa mendapatkan beberapa informasi tambahan di, misalnya, dokumentasi dari cache-long-line-scans(berganti nama menjadi cache-long-scans24.4).

Anda dapat mencoba dan melihat apakah pengaturan bidi-paragraph-directionuntuk left-to-rightmeningkatkan kecepatan untuk Anda [pengaturan bidi-display-reorderinguntuk nil, tidak lebih atau kurang sama tetapi hanya dimaksudkan untuk tujuan / debugging internal yang]. Ini menghapus satu kontributor signifikan untuk pemindaian garis, tetapi sayangnya bukan satu-satunya.

Opsi terbaik adalah menambahkan baris baru. Anda dapat mengirim file JSON melalui mis. python -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'Untuk menambahkan baris baru dan meningkatkan keterbacaan secara umum.

Jorgen Schäfer
sumber
4
Karena penasaran, apakah ini sesuatu yang tidak dapat diperbaiki secara algoritmik?
PythonNut
9
Saat memilih struktur data yang mendasari editor, Anda harus memilih antara pro dan kontra tertentu. Emacs menggunakan buffer gap , yang merupakan struktur data yang sangat ruang efisien untuk penyisipan dan penghapusan, tetapi membuat operasi berbasis garis lebih lambat karena Anda harus memindai secara berurutan untuk baris baru. Emacs dapat menggunakan struktur data yang berbeda, tetapi itu akan membuat operasi lain lebih lambat. Emacs sudah menggunakan cache baris, tetapi itu tidak benar-benar membantu dalam semua situasi. Jadi, tidak mudah ditingkatkan secara algoritmik, tetapi membuat profil dan mengoptimalkan tidak ada salahnya. :-)
Jorgen Schäfer
4
(setq-default bidi-display-reordering nil)- beberapa pengguna mungkin tidak menyadari bahwa ini adalah variabel penyangga-lokal, yang mungkin memerlukan pengaturan default sejauh yang diinginkan pengguna sebagai global. Saya berharap saya akan menambahkan itu ke init.eltahun - tahun yang lalu ... tapi setidaknya itu ada di sana sekarang. Terima kasih banyak!!!
hukum
Dalam kasus saya, itu bukan perbaikan besar (garis json sangat panjang dengan badan dokumen base64) tetapi banyak membantu pada pembekuan beign
anquegi
1
Pemelihara Emacs saat ini, Eli, yang menulis kode BIDI, menulis ini tentang mematikan bidi-display-reordering: "Satu komentar yang saya miliki adalah bahwa menonaktifkan bidi-display-reordering ... menempatkan mesin display dalam keadaan yang tidak diuji, dan dapat menyebabkan ketidakkonsistenan. dan bahkan bug (karena beberapa bagian dari kode ditulis dengan asumsi bahwa variabel ini tidak pernah nol). "
Clément
18

Saya melakukan beberapa percobaan singkat dengan ini menggunakan salinan jquery yang diperkecil. font-lock-modedan flycheck-modekeduanya berkontribusi terhadap kelambatan, seperti yang terjadi js2-mode, dan prettify-symbols-mode. line-number-modedan column-number-modememiliki efek kecil. Pernah saya mematikan semua mode yang berbeda meskipun kinerjanya relatif tajam. Gunakan C-h mdan mulai nonaktifkan berbagai mode yang diaktifkan, atau coba alihkan saja fundamental-mode.

Menariknya menggunakan hexl-modesaya bisa terbang melalui file tanpa masalah, meskipun kolom jelas cukup pendek. Sayangnya semuanya visual-line-modesangat melambat.

Dugaan saya adalah bahwa tabel sintaks senang berhenti memproses di akhir baris, dan ketika itu semua pada satu baris itu harus mem-reparsing semuanya pada setiap pembaruan.

dgtized
sumber
2
Bisakah Anda membuka laporan bug pada pelacak Flycheck? Saya cukup yakin kami tidak ingin antrean panjang menyebabkan masalah, dan Emacs + Flycheck seharusnya tidak lebih buruk dari Emacs (yang masih sangat buruk).
Clément
16

Saya telah mengunggah http://www.emacswiki.org/emacs/OverLongLineMode

Pustaka ini memungkinkan Anda untuk menetapkan ambang batas panjang garis sederhana di mana varian fundamental-modeakan digunakan untuk file alih-alih mode normal (hanya untuk mode pemrograman).

Secara potensial sesuatu di sepanjang garis ini dapat ditambahkan ke Emacs secara default, tetapi ini bisa menjadi solusi sementara untuk masalah utama Emacs yang lambat hingga merangkak saat menemukan file seperti itu.

nb Ini merupakan peningkatan pada kode yang awalnya saya posting dalam jawaban ini, tetapi masih dalam proses. Pengujian sudah minimal. Komentar disambut.

Saran untuk mode utama lain (selain css-mode) yang di prog-modeterima untuk mendukung secara default juga diterima.

phils
sumber
1
Sekarang semakin ditingkatkan, dan secara memalukan namanya diubah menjadi so-long.el :) (tautan di atas akan mengarahkan ulang). Ada lagi yang bisa dilakukan dengan ini, tetapi 100% fungsional dan berguna apa adanya.
phils
Ini adalah solusi yang sangat bagus (akan senang melihatnya di MELPA), tetapi contoh Emacs saya masih sangat lambat ketika membuka one_line.json. Saya pikir ini akan jauh lebih cepat jika tidak mengaktifkan asli mode utama.
Wilfred Hughes
3
Membaca ulang ini dan menggunakan file one_line.json Anda dari pertanyaan, saya menyerah menunggu default-config Emacs 25.3 dan 26.0.91 untuk merespons setelah meminta mereka untuk membuka file itu (setelah menunggu lebih dari satu menit), sedangkan saya sendiri konfigurasi dengan so-long.elaktif membuka file dalam waktu kurang dari 2 detik. Sebenarnya mengedit file masih sangat bermasalah (misalnya mencoba pindah ke 'baris berikutnya' akan memakan waktu yang sangat lama), tetapi bagaimanapun ini mengembalikan kepercayaan saya pada kegunaan perpustakaan yang saya tulis, jadi saya harus melanjutkan rencana saya untuk tambahkan ke GNU ELPA ...
phils
1
Apakah sudah dalam (M) ELPA?
binki
3
Laporan status: versi 1.0 dari so-long.el(dengan berbagai peningkatan) dimasukkan dalam versi pengembangan Emacs 27 saat ini, dan akan tersedia (untuk versi Emacs sebelumnya) melalui GNU ELPA suatu saat dalam waktu dekat.
phils
7

Saya berharap Anda akan menemukan bahwa perbedaannya adalah karena font-lock. Ketika fontification akan dilakukan pada subset dari file yang terlihat di jendela, itu melanjutkan dengan terlebih dahulu memperluas wilayah fontification sehingga akan mencakup unit semantik penuh. Lihat font-lock-extend-region-functionskode untuk ini. Ini umum untuk ini termasuk memperluas wilayah untuk memasukkan garis penuh. Ketika garis sangat panjang, ini dapat menyebabkan fontifikasi dilakukan di banyak konten yang jauh lebih besar daripada yang sebenarnya terlihat.

Selain itu, ketika baris baru sendiri memiliki informasi semantik, ketidakhadiran mereka kadang-kadang dapat berarti bahwa pola regexp untuk kunci font harus memindai lebih lanjut untuk menentukan apakah mereka cocok atau tidak.

sanityinc
sumber
7

Saya biasanya membuka gulungan antrean panjang dan lekukan oleh tag (seperti HTML, XML, JSON).

Untuk memungkinkan operasi seperti itu saya tambahkan:

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

Saya membagi line dengan regex, untuk XML itu: C-M-% >< RET >NL< RET !.

Setelah Emacs memecah garis panjang - dimungkinkan untuk mengaktifkan banyak *-modeskode dan indentasi ulang.

Sebagai catatan: Bagaimana mencegah perlambatan ketika proses yang lebih rendah menghasilkan garis panjang?

gavenkoa
sumber
4

Saya membuat solusi sendiri untuk masalah ini di sini: https://github.com/rakete/too-long-lines-mode

Saya tidak puas dengan solusi phils yang mengganti buffer dengan garis yang sangat panjang ke mode-fundamental, saya menginginkan solusi yang memungkinkan saya menjaga penyorotan sintaks dan fitur mode utama lainnya. Jadi saya membuat mode minor yang menggunakan overlay untuk menyembunyikan sebagian besar karakter dari garis yang terlalu panjang.

Itu mengatasi masalah dan membuat emacs dapat digunakan bahkan dalam buffer dengan garis yang sangat panjang, tanpa harus kembali ke mode fundamental.

Andreas Raster
sumber
2

Dalam pengaturan Emacs saya, saya memiliki mode dengan fontifikasi khusus, yaitu tempat saya mengatur font-lock-defaults. Satu halaman ke bawah akan menggunakan 30 detik untuk menampilkan bagian dari 30000 baris karakter. Perlambatan ini diperbaiki dengan mengurangi backtracking regexp. Dari pada:

  (". * berakhir dengan perintah tidak lengkap *" 0 font-lock-comment-face)

melakukan hal ini

  ("^. \ {1,80 \} berakhir dengan perintah tidak lengkap *" 0 font-lock-comment-face)
Axel Bregnsbo
sumber
Ini bukan jawaban untuk pertanyaan, yang tidak secara khusus tentang font-lock-defaultsatau pencocokan regexp.
Drew
1
@Drew Kurang dari regex yang ideal adalah membuat font-mengunci lambat pada garis panjang meskipun ...
wasamasa
1
@wasamasa: Ya. Pertanyaannya sendiri terlalu luas, IMO. Ada banyak hal yang dapat memperlambat Emacs (dan untuk tindakan apa?) Ketika terlibat dalam antrian panjang.
Drew
3
Saya tidak berpikir pertanyaannya adalah luas ("mengapa garis panjang membuat Emacs lambat")? Saya juga tidak berpikir bahwa jawabannya tidak menjawab pertanyaan (" salah satu alasan yang mungkin adalah regexps suboptimal"). Jawaban lain dapat menjawab alasan lain. Membuka file dengan garis panjang bukan untuk memperluas topik hanya karena itu mungkin bermasalah karena berbagai alasan, kadang-kadang Anda memiliki file seperti itu dan Anda harus melihatnya, sebaiknya menggunakan Emacs.
tarsius
1

Dalam buffer mode shell saya (Mx shell), saya menemukan diri saya sed -r 's/(.{2000}).*/\1/' -uuntuk menghindari garis panjang.

David Chandler
sumber
Ini menjawab bagian kedua dari pertanyaan: bagaimana cara meningkatkan kinerja. Itu tidak membahas bagian pertama (yang OK): " Mengapa Emacs memiliki kinerja yang buruk dengan garis panjang ?"
Drew
0

Saya menggunakan fungsi berikut untuk membuka dired-modefile besar dengan garis panjang:

(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)
Dodgie
sumber
0

Berikut ini solusinya, yang diambil dari 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)))))
clemera
sumber
Di Emacs pada 24,4 yang longlines-modeditandai sebagai usang oleh visual-line-mode.
Alexander I.Grafov
Namun kedua fitur tersebut melakukan hal-hal yang sangat berbeda di belakang layar, dan visual-line-modetidak membantu dengan masalah yang dipermasalahkan, sedangkan yang longlines-modedilakukan. Untuk alasan ini, saya berharap bahwa longlines.el akan dikembalikan ke status yang tidak usang.
phils