一个理论上可以提高 linum-mode 速度的方式

看了下 linum-mode 的实现 自己在 scratch buffer 一万行处(自己dotimes insert行什么的)执行

(benchmark-run 1000 (line-number-at-pos)) ;; 1.293795s
(benchmark-run 1000 (string-to-number (format-mode-line "%l"))) ;; 0.004484s

因为 (line-number-at-pos) 是通过 elisp 来一行一行统计行数来得到当前行数的,而 format-mode-line 是 build-in 的函数。所以后者在速度上优于前者。

所以理论上,可以直接

 ;; 不推荐使用,原因看下面
 (defun line-number-at-pos ()
    "Much faster line-number-at-pos"
    (string-to-number (format-mode-line "%l")))

  (setq line-number-display-limit-width 2000000)

来获取更快的速度。

当然以上都只是理论上

我看了下 linum-mode 的实现,它只针对当前显示的区域进行更新,而且 line-number-at-pos 只执行了一次(上面执行了1000次)所以

  • linum-mode 的卡顿真的存在么,还是我们错怪了它(我在这个10000行的buffer里未能察觉到卡顿,是要求什么特有的mode还是超长行什么的?),有没有什么方法稳定的复现这种卡顿

  • 如果存在,究竟是因为什么原因呢

3 个赞

说明 line-number-at-pos 不应该被重复调用,比如要统计行号信息的话,像下面这么用就会非常低效:

(save-excursion
  (goto-char (window-start))
  (while ...
    (line-number-at-pos)
    ...))

在我的印象中,format-mode-line 的结果似乎依赖于 redisplay(仅能用在 mode-line 上),结果并不稳定,并不是能完全替代前者。


Emacs 自带的 nlinum-mode 试图解决 linum-mode 低效的问题。或许值得一试,我还没怎么试过,因为我从来就不喜欢显示行号。

nlinum-mode 的实现方式就是加了个缓存, linum-mode 目前的方式暂时还是。。昂特别低效。

format-mode-line 在没有显示的 buffer 中不能用来取代 line-number-at-pos

不对我又看了下现在 linum-mode 的实现,已经没有重复调用了,只是调用了一次。

那么 linum-mode 目前究竟是否还存在性能问题?

如果我没记错的话,nilnum-mode 主要卖点是用 jit-lock-register 来注册更新函数,使其只在 font-lock 更新 buffer 某部分的 fontification 的时候调用,cache 只是其中加速的一个办法,并不是和 linum-mode 的主要区别。至于 nlinum-mode 是否真的快,快多少,没看到具体数据。

不过行号在大文件的时候确实是造成卡顿的一个重要原因。。。虽然我已经好久不用了。