如何防止过长的行使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是JSON的18MiB,没有任何换行符。pretty_printed.json添加了换行符和空格,使其成为41MiB。

但是,在Emacs中以Javascript模式和Fundamental模式打开时,分成多行的较大文件的速度要快得多。

为什么Emacs的行数这么少,但实际上它的字节数却少呢?在不重新格式化Emacs外部数据的格式的情况下,我能做些什么来提高性能?


2
并不是一个真正的答案,但可能有用:View Large Files(vlf)是次要模式,旨在通过批量加载来帮助编辑大型文件。免责声明:我从未使用过它,也不知道它是否也可以批量处理长行。
elemakil 2014年

3
知道这种行为后,尤其是在试图防止自己读取长行记录的日志时,我经常$ tail -f /some/file | fold -s在shell缓冲区中做类似的事情。显然,这不利于编辑,但对阅读有很大帮助。
wvxvw

Answers:


50

Emacs对长行的处理不是很好的优化。对于许多操作,Emacs必须重复扫描整条线。例如,要显示一条线,Emacs必须找出该线的高度,这需要扫描整条线以找到最高的字形。此外,扫描双向显示会占用大量时间。您可以在docstring cache-long-line-scanscache-long-scans在24.4中重命名)的文档字符串中获得一些其他信息。

您可以尝试查看设置bidi-paragraph-direction是否left-to-right可以提高速度[设置bidi-display-reorderingnil,或多或少都一样,但仅用于内部/调试目的]。这消除了行扫描的一个重要贡献者,但不幸的是,不是唯一的一个。

最好的选择是添加换行符。您可以通过管道传输JSON文件,例如python -c 'import json, sys ; json.dump(json.load(sys.stdin), sys.stdout, indent=2)'以添加换行符并总体上提高可读性。


4
出于好奇,这是无法通过算法改进的吗?
PythonNut

9
在选择编辑器的基础数据结构时,您必须在某些优缺点之间做出选择。Emacs使用间隙缓冲区gap buffer),这是一种高度节省空间的数据结构,用于插入和删除,但是由于必须逐行扫描换行符,因此它会使基于行的操作变慢。Emacs可以使用其他数据结构,但这会使其他操作变慢。Emacs已经使用了行缓存,但这并不能在所有情况下都有用。因此,在算法上不容易改进,但剖析和优化永远不会受到伤害。:-)
JorgenSchäfer'16

4
(setq-default bidi-display-reordering nil)-有些用户可能没有意识到这是局部缓冲区变量,在用户希望它是全局变量的情况下,可能需要默认设置。我希望我可以在init.el几年前添加它,但是至少现在就可以了。非常感谢你!!!
法律列表'17

就我而言,这不是一个很大的改进(带有base64文档正文的真正的json行很长),但是对良性冻结有很大帮助
anquegi

1
当前的Emacs维护者Eli编写了BIDI代码,其中写了有关关闭的信息bidi-display-reordering:“我的一个评论是,禁用bidi-display-reordering…会使显示引擎处于未经测试的状态,并且可能导致不一致甚至是错误(因为代码的某些部分是在假定该变量永远为零的前提下编写的)。”
克莱门特

18

我使用缩小的jquery进行了一些简短的实验。font-lock-modeflycheck-mode都导致缓慢js2-mode,和prettify-symbols-modeline-number-modecolumn-number-mode有轻微的影响。一旦我关闭了所有不同的模式,尽管性能相对敏捷。使用C-h m并开始禁用已启用的不同模式,或者尝试仅切换到fundamental-mode

有趣的是hexl-mode,尽管显然列很短,但我可以毫无问题地浏览文件。不幸的是,visual-line-mode确实放慢了一切。

我的猜测是语法表乐于在行尾停止处理,并且当它全部在一行上时,它必须在每次更新时重新解析所有内容。


2
您可以在Flycheck的跟踪器上打开错误报告吗?我敢肯定,我们不希望冗长的线引起问题,并且Emacs + Flycheck应该不会比Emacs差(这仍然很糟糕)。
克莱门特

16

我上传了http://www.emacswiki.org/emacs/OverLongLineMode

该库使您可以设置简单的线长阈值,超过该阈值fundamental-mode将使用一个变体而不是普通模式(仅对于编程模式)用于文件。

默认情况下,可能会在这些方面添加一些内容,但这可以作为Emacs遇到这样的文件时缓慢爬行的主要问题的临时解决方法。

注意:这是对我最初在此答案中发布的代码的改进,但仍在进行中。测试很少。欢迎发表评论。

也欢迎提出其他(除css-mode)非prog-mode衍生主模式默认支持的建议。


1
现在进一步改进,可耻地重命名为so-long.el :)(上面的链接将重定向)。可以做更多的事情,但是它是100%实用且有用的。
菲利浦斯

这是一个非常不错的解决方案(希望在MELPA上看到它),但是打开one_line.json时,我的Emacs实例仍然非常慢。我认为,如果不首先激活原始的主要模式,它将明显更快。
Wilfred Hughes

3
重新阅读此内容并使用问题中的one_line.json文件,我放弃了等待默认配置的Emacs 25.3和26.0.91在要求他们打开该文件(等待一分钟后)后做出响应,而我放弃了so-long.el激活配置会在2秒内打开文件。实际上,编辑文件仍然存在很大的问题(例如,尝试移至“下一行”将花费很长的时间),但这确实恢复了我对编写的库的有用性的信念,因此我应该恢复计划它添加到GNU ELPA ...
菲尔斯

1
它在(M)ELPA中吗?
宾基

3
状态报告:so-long.elEmacs 27的当前开发版本中包含1.0版(具有许多增强功能),并将在不久的将来通过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。向下翻一页将使用30秒来显示30000个字符行的一部分。通过减少正则表达式回溯可以解决此问题。代替:

  (“。*以不完整的命令结尾*” 0 font-lock-comment-face)

做这个

  (“ ^。\ {1,80 \}以不完整的命令结尾*” 0 font-lock-comment-face)

这不是问题的答案,后者不是专门针对正则font-lock-defaults表达式或正则表达式的。
提请

1
@Drew小于理想的正则表达式虽然使长行上的字体锁定变慢...
wasamasa

1
@wasamasa:是的。国际海事组织,这个问题本身太广泛了。当涉及长行时,有很多事情可能会使Emacs变慢(以及要执行哪些操作?)。
Drew

3
我认为问题不是广泛的(“为什么排长队会使Emacs变慢”)?我也不认为答案没有解决这个问题(“ 一个可能的原因是不理想的正则表达式”)。其他答案可以解决其他原因。打开长行的文件并不会扩大主题的范围,仅仅是因为由于多种原因这可能会带来问题,有时您拥有这样的文件,您必须查看它们,最好使用Emacs。
tarsius

1

在我的shell模式缓冲区(Mx shell)中,我发现自己在进行管道处理sed -r 's/(.{2000}).*/\1/' -u以避免长行。


这回答了问题的第二部分:如何提高性能。它没有解决第一部分(没问题):“ 为什么Emacs的行长性能如此差?”
Drew

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 longlines-mode开始,在Emacs中,标记为已过时visual-line-mode
亚历山大一世·格拉夫夫

但是,这两个功能在幕后做了非常不同的事情,而visual-line-mode对于所涉及的问题却无济于事longlines-mode。因此,我希望longlines.el将恢复为不推荐使用的状态。
菲尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.