Як запобігти надзвичайно довгим лініям робити Emacs повільним?


72

Я бачу надзвичайно різну продуктивність залежно від кількості нових рядків у файлі, який я відвідую.

Ось приклад. У мене є два файли 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

Це два файли JSON з однаковим вмістом. one_line.jsonстановить 18 Мбіт JSON без будь-яких нових рядків. pretty_printed.jsonдодано нові рядки та пробіли, що робить його 41MiB.

Однак більший розділений файл на багато рядків набагато швидше відкриється в Emacs, як в режимі Javascript, так і в основному.

Чому Emacs має таку низьку продуктивність із довгими рядками, оскільки насправді менше байтів? Чи можу я щось зробити для підвищення продуктивності без переформатування даних поза Emacs?


2
Насправді не відповідь, але може бути View Large Filesкорисною : (vlf) - це другорядний режим, який спрямований на допомогу з редагуванням великих файлів, завантажуючи їх у пакети . Відмова: Я ніколи не використовував його, і не знаю, чи він обробляє довгі рядки також партіями .
elemakil

3
Знаючи таку поведінку, і особливо, намагаючись захистити себе від читання журналу, який випинає довгий рядок, я часто роблю щось на зразок $ tail -f /some/file | fold -sбуфера оболонки. Очевидно, це не добре для редагування, але дуже допомагає при читанні.
wvxvw

Відповіді:


50

Робота з довгими лініями Emacs не дуже оптимізована. Для ряду операцій Emacs має повторно сканувати всю лінію. Наприклад, щоб відобразити лінію, Emacs має визначити висоту лінії, що вимагає сканування всієї лінії, щоб знайти найвищий гліф. Крім того, сканування двонаправленого дисплея з'їдає багато часу. Ви можете отримати додаткову інформацію в, наприклад, доктрині cache-long-line-scans(перейменованому cache-long-scansв 24.4).

Ви можете спробувати і подивитися , якщо установка bidi-paragraph-directionдля left-to-rightпокращує швидкість для вас [призахідного bidi-display-reorderingдо nil, робить більш-менш те ж саме , але призначений тільки для внутрішніх цілей / налагодження]. Це видаляє одного істотного учасника сканування рядків, але, на жаль, не єдиного.

Найкращий варіант - додавання нових рядків. Ви можете передавати файл 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років тому ... але, принаймні, це є зараз. Дуже дякую !!!
законник

У моєму випадку це був не великий імпровізатор (дійсно довгі рядки json з корпусом документів base64), але багато допомагає при заморожуванні
anquegi

1
Поточний супровід Emacs, Елі, який написав BIDI-код, пише про відключення bidi-display-reordering: "Один із коментарів, який я маю, - це відключення переназначення bidi-дисплея ... переводить двигун дисплея в стан, який не перевіряється, і може викликати невідповідності і навіть помилки (тому що деякі частини коду були написані під припущенням, що ця змінна ніколи не дорівнює нулю). "
Clément

18

Я зробив кілька коротких експериментів з цим, використовуючи мінімізовану копію jquery. font-lock-modeі flycheck-modeобидва сприяли повільності, як js2-modeі prettify-symbols-mode. line-number-modeі column-number-modeмала незначну дію. Одного разу я вимкнув усі різні режими, хоча продуктивність була досить швидкою. Використовуйте C-h mта починайте відключати різні включені режими або спробуйте просто перейти на fundamental-mode.

Цікаво, що за допомогою hexl-modeя міг пролетіти через файл без жодних проблем, хоча очевидно колонки були досить короткими. На жаль, visual-line-modeсправді сповільнили справи.

Я здогадуюсь, що синтаксична таблиця рада зупинити обробку в кінцях рядка, і коли вона знаходиться в одному рядку, вона повинна переглядати все під час кожного оновлення.


2
Чи можете ви відкрити звіт про помилку в трекері Flycheck? Я впевнений, що ми не хочемо, щоб довгі рядки викликали проблеми, а Emacs + Flycheck не повинен бути гіршим за Emacs (що все ще досить погано).
Clément

16

Я завантажив http://www.emacswiki.org/emacs/OverLongLineMode

Ця бібліотека дозволяє встановити прості пороги довжини рядка, понад які варіант fundamental-modeфайлу буде використовуватися для файлу замість його звичайного режиму (лише для режимів програмування).

Потенційно щось за цими рядками може бути додане до Emacs за замовчуванням, але це може бути тимчасовим вирішенням первинної проблеми, що Emacs сповільнюється до повзання при зустрічі з таким файлом.

nb Це вдосконалення щодо коду, який я спочатку розміщував у цій відповіді, але все ще незавершений. Тестування було мінімальним. Коментарі вітаються.

Запропоновані пропозиції щодо інших (крім css-mode) prog-modeосновних режимів, які не використовуються для підтримки за замовчуванням.


1
Тепер далі вдосконалено і соромно перейменовано на so-long.el :) (вищенаведене посилання буде переспрямовано). З цим можна зробити більше, але це 100% функціонально і корисно.
філ

Це дійсно приємне рішення (хотілося б побачити це на MELPA), але мій екземпляр Emacs все ще надзвичайно повільний при відкритті one_line.json. Я думаю, що це було б значно швидше, якби він не вперше активував оригінальний основний режим.
Вільфред Х'юз

3
Перечитавши це та скориставшись вашим файлом one_line.json із запитання, я відмовився чекати відповіді Emacs 25.3 та 26.0.91 за замовчуванням на відповідь після того, як попросив їх відкрити цей файл (почекавши більше хвилини), тоді як мій власний config з so-long.elактивним відкриттям файлу за 2 секунди. Насправді редагування файлу все ще дуже проблематично (наприклад, спроба перейти до «наступного рядка» займе вкрай багато часу), але, тим не менш, це відновить мою віру в корисність бібліотеки, яку я написав, тому я повинен відновити свої плани щодо додайте його до GNU ELPA ...
phils

1
Це ще в (M) ELPA?
бінкі

3
Звіт про стан: версія 1.0 so-long.el(із численними вдосконаленнями) включена у поточну версію розробки Emacs 27 та буде доступна (для більш ранніх версій Emacs) через GNU ELPA якось найближчим часом.
філ

7

Я сподіваюся, що ви побачите, що різниця пов'язана з font-lock. Коли fontification повинен бути виконаний на підмножині файлу, який є видимим у вікні, він продовжується, спочатку розширивши область fontification таким чином, що вона буде включати повні семантичні одиниці. Дивіться 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. На одній сторінці вниз знадобиться 30 секунд, щоб відобразити частину 30000 символьних рядків. Це уповільнення було виправлено за рахунок зменшення зворотного відстеження. Замість:

  (". * закінчилося неповною командою *" 0 шрифт-блокування-коментар-обличчя)

зробити це

  ("^. \ {1,80 \} закінчився неповною командою *" 0 шрифт-замок-коментар-обличчя)

Це не є відповіддю на питання, яке конкретно не стосується font-lock-defaultsабо не відповідає регулярному вибору.
Дрю

1
@Drew Менше, ніж ідеальний регулярний вираз , робить блокування шрифту повільним на довгих рядках ...
wasamasa

1
@wasamasa: Так. Питання саме по собі занадто широке, IMO. Є багато речей, які можуть уповільнити Emacs (і для яких дій?), Коли задіяні довгі рядки.
Дрю

3
Я не думаю, що питання полягає в широкому ("чому довгі рядки роблять Emacs повільним")? Я також не думаю, що відповідь не стосується питання (" однією з можливих причин є субоптимальні регулярні виразки"). Інші відповіді можуть стосуватися інших причин. Відкриття файлу з довгими рядками не є широкою темою лише тому, що це може бути проблематичним з різних причин, іноді у вас є такі файли, і вам доводиться їх переглядати, бажано, використовуючи Emacs.
Тарсій

1

У своїх буферах оболонки в режимі оболонки (оболонка Mx) я опиняюсь так, sed -r 's/(.{2000}).*/\1/' -uщоб уникати довгих рядків.


Це відповідає на другу частину питання: як покращити продуктивність. Він не стосується першої частини (що в порядку): " Чому Emacs має таку низьку продуктивність із довгими рядками ?"
Дрю

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

У Emacs станом на 24.4 longlines-modeпозначено як застаріле visual-line-mode.
Олександр Іванович Графов

Однак обидві функції роблять дуже різні речі за лаштунками, і visual-line-modeце не допомагає в питанні, про яке йдеться, тоді як longlines-mode. З цієї причини я сподіваюся, що longlines.el буде відновлений до неактуального статусу.
філс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.