lazycat的实现相当于是减少load-path 中路径的数量,一般来说用package.el管理的话包所在目录就是单层,不用过滤,所以不是非常复杂的目录嵌套可能起不到太大的效果。
实际上,emacs 目前的实现的缓存构建过程是非常快的,我估计不会超过10ms。我说的另一种实现是指直接把包定位到目录,然后那个filter函数返回单个目录而不是要走一遍过滤过程。
简单来说就是目前的实现的工作流程是构建目录到目录内文件列表的缓存,然后在原先根据列表遍历查找之前用 try-completion 过滤掉不相关的路径,实际上我们还是遍历了一遍路径列表,但不涉及系统调用所以远快于直接便利。
我的意思是直接构建一个从包符号名到目录的映射表,启动emacs时加载这个表,当加载某个包时直接使用表映射到唯一的路径,这可能能省掉try-completion 遍历整个load-path 列表的时间
2 个赞
今天又用procmon优化了下(emacs启动的时候会从PATH去找很多不需要的可执行程序), 现在chenbin的配置启动速度能到0.7秒 
(用的 Eason0210的预编译版本,非native comp)
2 个赞
不知道怎么回事,今天在完全默认的情况下使用我的配置启动 Emacs 的基准时间(指没有采用任何优化手段)的时间是 4.8~5.0s,这些测试是在昨天我编译的 emacs-optimize_load 进行的。
- 仅使用
load-path-filter-cache-directory-files,启动时间在 4.1~4.3s
- 仅使用
(load-write-cache-file),启动时间在 3.3~3.5s。
又看了一遍你的代码,从纯 Elisp 层面应该是拿不到 load 某个包的具体路径的,必须利用 openp 的 found 参数,我的思路就只能是对 load-path-filter-cache-directory-files 返回的结果做缓存。具体存储实现我选择了 alist,它解析起来比 hashtable 快。具体代码如下:
(defvar yy/cache-2 nil)
(defun yy/load-cache ()
(setq yy/cache-2
(condition-case e
(car (read-from-string
(with-temp-buffer
(insert-file-contents
(file-name-concat user-emacs-directory "ycache.eld"))
(buffer-substring (point-min) (point-max)))))
(error nil))))
;;(make-hash-table :test #'equal))))
(yy/load-cache)
(defun yy/load-path-filter (path file suffixes)
(if-let* ((ls (with-memoization (alist-get file yy/cache-2 nil nil #'equal)
(let ((res (load-path-filter-cache-directory-files path file suffixes)))
(if (eq res path) nil res)))))
ls path))
(defun yy/write-cache ()
(interactive)
(when yy/cache-2
(with-temp-file (file-name-concat user-emacs-directory "ycache.eld")
(pp yy/cache-2 (current-buffer)))))
(yy/load-cache)
(setq load-path-filter-function #'yy/load-path-filter)
思路很简单,yy/load-cache 负责从文件加载缓存,yy/write-cache 负责写入。yy/load-path-filter 实质上就是给 load-path-filter-cache-directory-files 套了个装饰器,做了“二级缓存”。把上面的代码放在配置文件的开头,在启动一次 Emacs 后执行 yy/write-cache 即可完成缓存持久化,下次启动时就会利用缓存。你可以比较容易地通过修改上面的 yy/load-path-filter 中的 alist-get 和 yy/load-cache 函数来将存储格式换成 hashtable 或 plist,下面是我的测试结果:
- alist 3.5s~3.7s
- hashtable 3.45s~3.6s
- plist 3.4s~3.55s
(我也不是很清楚为什么 plist 最快…)
当然上面的代码还有很大的改进空间,这就是个 POC,我没怎么处理各种异常情况。
顺便问下怎么做的。
1 个赞
emacs启动的时候会给这里的每个名字,比如google-chrome-stable拼接好几种后缀, 然后遍历PATH的每个目录判断是否存在, 我不需要这些功能
就写个hello程序,重命名后放在c:\path里面, 然后把这个目录加到环境变量PATH的最开头(里面有几个大小不是13k的是我需要的,不用管)
另外我用的这个预编译的emacs版本, 确实比其他的都要快
你可以下载procmon监控看看, 用法很简单, 设置过滤器后启动监听,打开emacs就行
1 个赞
不过有点奇怪的是, 不知道为啥会触发一次gc
看配置里面,都是在配置开头把阈值设高,(这个值应该触发不到吧.) 配置结束时才恢复gc设置
具体的打印到 *message* 的代码是?
以及 0.5 秒的那次测试的具体配置方法是仅使用我的那段代码吗?还是配合了你之前的代码。
(message "*** Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time (time-subtract after-init-time before-init-time)))
gcs-done)
Eason0210的预编译emacs + 你上面的代码片段 + chenbin的配置(我改了一些地方)
详细配置可以看这里 GitHub - heheda123123/dot_emacs: emacs config
1 个赞
上面的 init.el 中似乎包含恢复正常的 GC 参数的代码,恢复参数之后执行一次倒也正常。
恢复是设置的延迟4秒执行 
算了,这个问题不大,先不管了
Hash
31
我是用户,冷启动大概 3s → 0.7s,热启动 1s → 0.25s
确实有包 dump 了就会起不来,我都注释掉了
btw, doom-modeline 最近引入了不兼容 pdump 的变更(
btw, 如果是 native comp 用户,创建 dump 前,先把 eln-cache 文件夹删了
1 个赞
第三方包没有报错嘛? 有详细的配置说明可以参考吗?
(不过经过上面讨论后的优化, 现在的配置不用pdump可以做到冷启动0.5秒
很够用了
Hash
33
报错是不显示的,只有一个个二分查找(大概是 UCRT emacs 不会输出报错到 console 的老 bug)
可以参考我的配置和 Fu Yuan 的配置(如下)
1 个赞
Hash
35
你们主线用户可以用这个方法。我是正式版用户,用不上了。
(setq load-suffixes '(".elc" ".el"))
(setq load-file-rep-suffixes '(""))
这两句还是可以试下, 1 减少启动时间 2 减少第一次加载某个包的时间
2 个赞