尽管有很多软件包,如何改善启动时间?


19

TL; DR我的软件包太多,以至于影响了我的启动时间。如果您不相信这种情况,请继续阅读。


我的Emacs启动时间非常短。我不使用use-package,我只是设置了很多钩子和autoloads,所以几乎所有代码都被推迟了。实际上,整个过程加载起来通常不到半秒,尽管看上去好像一团糟。

然而,随着时间的推移,我发现我的启动时间变慢,令人费解。最终达到启动时间≥1秒的程度。我终于受够了,我深入探究了问题的根源。我最终注释掉了我的整个~/.emacs文件,发现启动时间仍然 ≥1秒。实际上,它只减少了大约0.2几秒钟,有时甚至更少。然后,我尝试emacs -q发现启动时间为〜0.1秒。

通过阅读Elisp手册的这一部分,我发现了为什么要这么emacs -q减少启动时间。显然emacs -q阻止了Emacs在启动时做三件事:

  1. 加载您的初始化文件
  2. 加载default.el文件
  3. 呼唤 package-initialize

我们已经排除了我的init文件,因为注释掉我的整个文件~/.emacs几乎没有任何作用。我不使用default.el文件,因此也排除了该文件。这package-initialize是造成性能下降的罪魁祸首。

为什么package-initialize要占用这么多启动时间?那是我问自己的第一个问题。我不是自动加载所有内容吗?嗯,是。但是,恰恰是问题。

我发现这篇文章解释了“激活”软件包包括读取自动加载文件和设置加载路径。当您有许多软件包时,这显然会导致I / O损失,因为您有许多要读取的自动加载文件和许多设置路径。不幸的是,没有这个,管理自动加载的任务就落在用户手中。换句话说,在不让package.el爬网文件系统自动加载文件和路径的情况下,我必须亲自管理该过程,这可能是一个乏味且容易出错的过程。

我宁愿不走那条路。我目前有116个软件包,其中有107个来自ELPA,其中25个是依赖项。我确信这个惊人的数字是对我的表现造成如此严重的影响。但是我很困惑,因为我不想删除任何软件包。

在这种情况下是否有任何补救措施可以使我的闪电启动时间恢复原状?


更新:

我们已经开始了一个新的线程emacs-devel关于邮件列表的一些 补丁斯特凡Monnier的(这些补丁的描述是这里)来解决这个问题。欢迎任何人测试他的补丁并提供反馈。

另一个更新:

似乎Stefan Monnier对这个问题不再感兴趣,或者他没有收到我的消息。我倾向于相信前者,这很好,尽管在这种情况下,我将感谢他的某种回应。无论如何,到目前为止,他为该问题编写的代码都运行良好。他的最新补丁可以在此处(对于Emacs 25.3)此处(对于Emacs master分支)找到。由于有了他的补丁程序,我在启动时间上看到了很好的改进,并且我对启动时间感到满意,因为它在不减少自定义功能的情况下尽可能地得到了优化。我希望这些修补程序能够在某个时候进入Emacs主线,但我想我(或其他人)现在必须为此承担火炬,而不是Stefan。在邮件列表中,我们有些关于版权转让和许可的问题。最初,我对此感到不舒服,但是由于理查德·斯托曼(Richard Stallman)和其他人的一些评论,版权分配可能没有我最初想象的那么严格。此外,我可能有可能将我的作品提交到公共领域,以替代版权转让。

无论如何,感谢Stefan到目前为止的补丁!我希望您会继续开发这些更改,但是如果没有,那就可以了,我可能会在某个时候继续开发它。我还要感谢其他所有为解决此问题提供见识和贡献的人。

另一个更新:

哇,该功能终于登陆了,将在Emacs 27中使用。感谢Stefan Monnier!


好问题。
提请

use-package是要这样做的方法。
Dodgie '18

不要试图淡化这个问题(启动延迟很重要!),但是请考虑将emacs作为守护程序/服务器运行,因此您只需支付启动费用一次。
GManNickG

1
@GManNickG我确实将Emacs作为服务器运行。不幸的是,我时不时地将Emacs推得太重或对其进行过多修改,重新启动是清理问题的最佳方法。发生这种情况时,我希望启动时间是最佳的。
GDP2

Answers:


13

package.el中的一种设计选择是尝试使事情“简单”。其中一部分是package-initialize搜索所有已安装的软件包,然后尝试找出应激活其中哪些软件包(根据固定和版本的最新性(如果同一软件包的多个版本可用)),然后加载每个激活包的<pkg>-autoloads.el文件。

因此,对于已安装的N个软件包,这意味着基本上读取了N个<pkg>-pkg.el软件包描述文件和N个<pkg>-autoloads.el文件。对于较大的Ns,这可能会成为一个严重的问题。另一个潜在的性能问题是,它将向中添加N个元素load-path,因此每次loadEmacs都将搜索N个目录时,每个目录的load速度都会变慢。

我们可以尝试多种方法来加快速度:

  • 提供某种预先计算~/.emacs.d/elpa/package-initialize.el(c)文件的方法,这是<pkg>-autoloads.el按正确顺序正确连接所有文件的结果。然后package-initialize可以在存在时加载该文件,然后跳过其他所有内容。然后你会需要一些方法来刷新/刷新package-initialize.el(c)包时,添加/更新/删除的文件,或者当你改变你package-pinned-packages或你的package-load-list。我认为可以通过对系统进行很少的更改来完成此操作(我认为真正需要更改的唯一事情是package-initialize,可以告诉它“仅激活”而不加载有关可用软件包的元数据)。

  • 提供一些方法来建立/操纵超级套餐,即包,其中将几个包成一个(所以只有一个加入元素的load-path,一个<pkg>-pkg.el和一个<pkg>-autoloads.el装)。这可能会增加执行难度(因为您不能仅激活超级包中包含的部分包,因此依赖性/版本分析可能很棘手)。

上述第一个选项应该是很容易实现,将使package-initialize 很多,当你安装了很多包快。如果您有兴趣尝试此操作,请随时向我寻求帮助。

FWIW,我刚刚尝试在测试设置中“手动”构建这样的大型自动加载文件。结果:虽然package-initialize耗时约0.9s,但加载mega-autoloads.el文件耗时0.3s,我可以通过let绑定load-source-file-function到nil 降低到0.2s,通过字节编译文件降低到0.1s。老实说,我希望能提高速度,但这仍然值得。

[编辑]这种“巨型自动加载”方法现在可以在Emacs的master分支中使用(在不久的将来成为Emacs-27)。它由新package-quickstart变量控制。


这些是一些非常有趣的想法。第一个听起来更扎实,挑战性也较小。第二个非常有趣,但是对于package.el开发人员来说,这听起来像是一份工作。对于从第一种选择开始,您有什么建议?我想看看我能做些什么,因为它似乎更可行。
GDP2

el-get使用单一的自动加载文件方法,基本上在大多数时间都可以使用。有些软件包的自动加载取决于评估它们所在的文件系统中的位置,这会带来麻烦。但是,我没有遵循“按正确的顺序”的意思,为什么自动加载的顺序却无关紧要(我没有认为对于当前package.el甚至是确定性的?
npostavs

@Stefan,如果可以的话,请在这里分享解决方案。
曼努埃尔·乌贝蒂

1
@npostavs:大多数<pkg>-autoloads.el文件仅设置自动加载,并且实际上并不关心顺序,但是并没有阻止它们随机执行其他操作的情况,package.el确实确保<pkg>依赖于其的软件包将在<pkg>其自身之前被激活。
斯蒂芬

1
关于此问题的另一个更新:我们在这里的邮件列表上开始了一个新主题,任何人都可以自由评论或测试Stefan的更改。
GDP2

6

您描述的有关package-initialize花费大量时间来加载的问题是一个众所周知的问题。这也是某些emacs框架试图通过手动加载自动加载来解决的问题之一。

我看到了两种解决您问题的方法。

  1. 编写(或从框架中提取)功能以设置路径并加载您感兴趣的软件包的自动加载。
  2. 使用明确针对速度的框架。我个人推荐DOOM emacs。有了这个框架,我将在大约1秒钟内加载200多个数据包。

推荐DOOM emacs的主要原因之一是该框架将软件包管理置于emacs之外。不要误解我的意思,软件包管理仍然是emacs,只是管理软件包是在标准用户会话之外完成的。这里的原理是:正常启动emacs时,我们应该能够假定所有软件包都已经存在并且已经可以加载。这样可以节省大量时间。DOOM Emacs提供一些种类的相当于apt-getpacman为Emacs。一旦安装了软件包,则每当emacs启动时,都假定它已经安装;无话可问。


Phew,很高兴得知这个问题不仅影响了我。感谢您将我指向DOOM Emacs。我将不得不仔细研究它,看看我可以适应自己的设置。
GDP2

我一直在玩DOOM emacs(并在可能的时候做出贡献)。如果您有任何问题,请随时与我联系。
UndeadKernel
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.