去掉exec-path-from-shell加快两秒启动时间

不要使用exec-path-from-shell这个package,经过我的测试它会导致2秒的启动延时。在shell中启动Emacs,可以直接把exec-path传到Emacs中。我创建了几个alias方便打字,大家可以参考下,在shell启动脚本中(.bashrc或.zshrc)中添加alias。

alias e25="/Applications/Emacs.app/Contents/MacOS/Emacs" #以后可以这么用e25 --debug-init
alias e25AndDisown="e25 &;disown;" #直接启动GUI,关闭终端也没有影响
alias ec25="/Applications/Emacs.app/Contents/MacOS/bin/emacsclient --create-frame" #总是创建frame #client
alias ec25tui="ec25 -nw" #在终端中显示

spacemacs的设置 我的spacemacs启动速度是2.5s,167 packages。如果用了exec-path-from-shell,启动速度肯定在4s以上。

;;在这里把它禁用
dotspacemacs-excluded-packages '(
                                exec-path-from-shell)

我觉得这个启动时间意义不大,打开 emacs 不关,或者使用 daemon 模式,就根本不用在意启动时间。

sublime text 够快了吧,开一堆插件一样启动很久。

我试了。没明显提高,还是10+秒

1 个赞

exec-path-from-shell 是通过执行你的 Shell 的配置来获得环境变量的,因此如果你的 Shell 配置比较复杂,自然会需要较多的时间。

比如我用的是 Bash,我的 ~/.bashrc 一百来行,比较简单。exec-path-from-shell 需要 0.9 秒

(use-package exec-path-from-shell
  :if (memq window-system '(ns mac))
  :ensure t
  :config (exec-path-from-shell-initialize))

Loading package exec-path-from-shell...
Configuring package exec-path-from-shell...done (0.909s)
Loading package exec-path-from-shell...done (0.926s)

我的环境变量都在 ~/.profile 中设置,并没有必要执行 ~/.bashrc,所以不需要 -i 选项,设置 exec-path-from-shell-arguments 去掉它,之后加载的时间就减少到了 0.4 秒

(use-package exec-path-from-shell
  :if (memq window-system '(ns mac))
  :ensure t
  :config
  (setq exec-path-from-shell-arguments '("-l"))
  (exec-path-from-shell-initialize))

Loading package exec-path-from-shell...
Configuring package exec-path-from-shell...done (0.392s)
Loading package exec-path-from-shell...done (0.397s)

另外,你也可以不用 exec-path-from-shell,直接手动设置环境变量。或者考虑到一般你的配置不变的话,环境变量的值也是不变的,所以可以持久化这一步骤,不用每次通过执行 Shell 配置来获得环境变量。

3 个赞

非常感谢。怪不得只有我发现exec-path-from-shell很耗时。确实我的启动脚本里面有很多东西,用了oh-my-zsh,zsh中又有很多配置,比如autojump

1 个赞

发现了导致Emacs 启动慢的原因了。 准备滚回去用 bash


结果还是在用 zsh。 不过已经卸了 oh-my-zsh。200来行的配置界面还是很好看。

我一开始就走在正确的道路上,Terminal.app 默认是 bash,只开两个窗口(其他应用最多也只开两个窗口,确保闭着眼睛按 ⌘-` 都知道会切换到哪个窗口。不看键盘打字叫盲打,不注视屏幕切换窗口应叫做盲切):

  • bash1 上跑 emacs
  • bash2 上 Tmux, 在 Tmux 跑 fish、管理多任务

内层 fish 所用的 rc,是由外层的 .bashrc 自动生成,所以这两层环境几乎一致。

2 个赞

跟用什么 Shell 没什么关系,如果 exec-path-from-shell 耗时比较多的话,可以把环境变量写到单独文件里,exec-path-from-shell 默认也是有提醒的。

不过本来就觉得oh-my-zsh启动太慢了。顺带把它处理了。

建议大家看看exec-path-from-shell-check-startup-files 这个变量 将 环境变量相关的配置放到 .zshenv (for zsh) or .profile(for bash) 中, 而不是放在 .zshrc 或.bashrc 中 然后将 exec-path-from-shell-arguments 变量中的 -i去掉
然后设置 exec-path-from-shell-variables只配置你想从shell获得的环境变量

(setq exec-path-from-shell-variables '("PATH" "MANPATH" "GOROOT" "GOPATH" "EDITOR" "PYTHONPATH"))

;; 设成nil 则不从 .zshrc 读 只从 .zshenv读(可以加快速度,但是需要你将环境变量相关的都放到 .zshenv 中,而非 .zshrc 中)
(setq exec-path-from-shell-check-startup-files nil) ;
(setq exec-path-from-shell-arguments '("-l" )) ;remove -i read form .zshenv
(exec-path-from-shell-initialize)

9 个赞

还真是从2.7秒提升到了2.3秒。

1 个赞

哈哈,提升了 15%

1 个赞

这些 shell 本来就慢,再加上一大堆酷炫的配置,电脑性能高些还不怎么觉得,老旧电脑 C-l 清屏都会延迟:

└⋊> time git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working tree clean
        0.01 real         0.00 user         0.00 sys

└⋊> time python --version
Python 2.7.10
        0.11 real         0.04 user         0.05 sys

└⋊> time ruby --version
ruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-darwin15]
        0.09 real         0.04 user         0.03 sys

└⋊> time node --version
v6.9.4
        0.12 real         0.04 user         0.05 sys
1 个赞

exec-path-from-shell执行的是这个命令 zsh -l -i -c "printf '__RESULT\\000%s\\000%s' '$PATH' '$MANPATH'"。可以用time准确地得到执行的时间。所以我标题党了,标题应该叫“去掉exec-path-from-shell加快1.679秒启动时间”

time zsh -l -i -c "printf '__RESULT\\000%s\\000%s' '$PATH' '$MANPATH'" #我这里提示1.679 total

最后我的解决方案:

;; 复用exec-path-from-shell内的一个方法,其实自己实现也可以
(defun exec-path-from-shell-setenv (name value)
  "Set the value of environment var NAME to VALUE.
Additionally, if NAME is \"PATH\" then also set corresponding
variables such as `exec-path'."
  (setenv name value)
  (when (string-equal "PATH" name)
    (setq eshell-path-env value
          exec-path (append (parse-colon-path value) (list exec-directory)))))
;;调用exec-path-from-shell-setenv,手动传入参数,每次修改PATH都要到这里修改一下。还好我修改不频繁
(exec-path-from-shell-setenv "PATH" "/Users/n/.cask/bin:/opt/theos/bin:/Users/n/wsybin:/usr/local/opt/coreutils/libexec/gnubin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin:/usr/local/git/bin:/Users/n/.rvm/bin")
2 个赞

求教是如何測試啓動時間的?

use-package 自带的,大于多少秒就显示出时间了

use-package 的话,可以调整选项 use-package-verbose。否则也可自行实现,如

(let ((now (current-time)))
  (require 'org)
  (float-time (time-subtract (current-time) now)))
     => 0.323736
3 个赞

好的謝謝:grinning:

:+1: 这个很有用。把环境变量都放 .zshenv ,并去掉 -i 选项,启动时间终于减少到 1 s 以下了。

1 个赞

虽然是挖坟,但是在 reddit 看到了这个讨论:https://www.reddit.com/r/emacs/comments/f8xwau/hack_replace_execpathfromshell/

感觉 doom 的方法不错,另外自己在 emacs 配置里手动设置环境变量感觉也挺实用的,毕竟环境变量大部分时候都是不会变化的👀

2 个赞