解決 Unable to resolve your shell environment in a reasonable time.

配圖源自 Freepik

一、背景

不知道什么時候起淘捡,我那服役了 5 年多的 MacBook Pro球榆,每次重啟后立刻喚醒 VS Code 的時候充易,總會彈出提示:

Unable to resolve your shell environment in a reasonable time. Please review your shell configuration.
無法在合理的時間內(nèi)解析 shell 環(huán)境。請檢查 shell 配置裁着。

打開 VS Code 的方式有:

  • 命令行啟動 code path/to/file
  • 點擊應(yīng)用圖標(biāo)

上述問題繁涂,僅在非命令行啟動才會出現(xiàn)。也就是說二驰,它就是解決問題的方式之一扔罪。但我想,更多人是通過點擊 LaunchPad 或 Dock 欄應(yīng)用圖標(biāo)啟動的桶雀。

二矿酵、原因

復(fù)現(xiàn)步驟:只要在 Shell 配置文件中添加一行 sleep 30(睡眠 30s唬复,實際上超過 10s 即可),然后重啟 VS Code 就能看到該提示全肮。

Resolving shell environment fails 可知:

通過非命令行方式啟用 VS Code 時敞咧,它會啟動一個小進程來運行 Shell 環(huán)境,也就是執(zhí)行 .bashrc.zshrc 配置文件辜腺。如果 10s 后休建,Shell 環(huán)境仍未解析完成或者由于其他原因?qū)е陆馕鍪。敲?VS Code 將會終止解析评疗,然后就會提示:Unable to resolve your shell environment in a reasonable time. Please review your shell configuration.

由于使用命令行啟動 VS Code测砂,它會繼承 Shell 環(huán)境變量,因此不會出現(xiàn)上述問題(#717)百匆。

至于為什么 VS Code 在啟動時要解析 Shell 砌些?從其描述上看,大概是因為像 task加匈、debug targets存璃、plugins 等功能需要讀取 Shell 環(huán)境變量。

因此矩动,只要確保 Shell 配置不出錯有巧,且解析時間在 10s 之內(nèi),就能解決問題了悲没。

官方給出的排查步驟如下:

The process outlined below may help you identify which parts of your shell initialization are taking the most time:

  • Open your shell's startup file (for example, in VS Code by typing ~/.bashrc or ~/.zshrc in Quick Open (?P)).
  • Selectively comment out potentially long running operations (such as nvm if you find that).
  • Save and fully restart VS Code.
  • Continue commenting out operations until the error disappears.

Note: While nvm is a powerful and useful Node.js package manager, it can cause slow shell startup times, if being run during shell initialization. You might consider package manager alternatives such as asdf or search on the internet for nvm performance suggestions.

把 Shell 配置文件中一些耗時操作給注釋掉以減小解析時間。這里 nvm 被點名了男图,沒錯示姿,我確實有用到它。

三逊笆、zsh 啟動耗時測試

本節(jié)以 zsh 為例栈戳。

首先,這里利用自帶的 time 命令來衡量命令執(zhí)行用時(包括 zsh)难裆。

$ /usr/bin/time /bin/zsh -i -c exit

        0.62 real         0.33 user         0.32 sys

time 命令結(jié)果輸出由 real_time子檀、user_timesys_time 組成:

  • real_time:表示從程序開始到程序執(zhí)行結(jié)束時所消耗的時間,包括 CPU 的用時和所有延遲程序執(zhí)行的因素的總和乃戈。其中 CPU 用時被劃分為 user 和 sys 兩部分褂痰。
  • user_time:表示程序本身以及它所調(diào)用的庫中的子進程使用的時間。
  • sys_time:表示由程序直接或間接調(diào)用的系統(tǒng)調(diào)用執(zhí)行的時間症虑。

但注意三者并沒有嚴(yán)格的關(guān)系缩歪。通常單核 CPU 是 real_time > user_time + sys_time,而多核 CPU 則是 real_time < user_time + sys_time谍憔,更多請看匪蝙。

以上 zsh 啟動時間僅 0.62s主籍,為了數(shù)據(jù)更準(zhǔn)確,使用 for 循環(huán)連續(xù)啟動 5 次:

$ for i in $(seq 1 5); do /usr/bin/time /bin/zsh -i -c exit; done

        0.66 real         0.34 user         0.35 sys
        0.64 real         0.34 user         0.34 sys
        0.66 real         0.34 user         0.36 sys
        0.66 real         0.34 user         0.36 sys
        0.65 real         0.34 user         0.35 sys

如果不加載 ~/.zshrc(使用 --no-rcs 參數(shù))看看有多快(以下顯示為 0 是因為太快了):

$ for i in $(seq 1 5); do /usr/bin/time /bin/zsh --no-rcs -i -c exit; done
        0.00 real         0.00 user         0.00 sys
        0.00 real         0.00 user         0.00 sys
        0.00 real         0.00 user         0.00 sys
        0.00 real         0.00 user         0.00 sys
        0.00 real         0.00 user         0.00 sys

另外逛球,zsh 提供了專門的 profiling 模塊用于衡量 zsh 各個函數(shù)的執(zhí)行用時千元。在 ~/.zshrc 配置文件中添加一行以加載 zprof 模塊。

# ~/.zshrc
zmodload zsh/zprof

接著使用 zprof 命令獲取各函數(shù)用時數(shù)據(jù):

$ zprof
num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    2         446.71   223.36   48.18%    190.57    95.28   20.55%  compinit
 2)    2         297.80   148.90   32.12%    170.88    85.44   18.43%  nvm
 3)    1         155.83   155.83   16.81%    155.83   155.83   16.81%  compdump
 4)    1         403.10   403.10   43.48%    105.29   105.29   11.36%  nvm_auto
 5)    1         112.56   112.56   12.14%    103.25   103.25   11.14%  nvm_ensure_version_installed
 6)  771          67.70     0.09    7.30%     67.70     0.09    7.30%  compdef
 7)    4          32.85     8.21    3.54%     32.85     8.21    3.54%  compaudit
 8)    1          30.02    30.02    3.24%     30.02    30.02    3.24%  is_update_available
 9)    2          42.88    21.44    4.63%     12.86     6.43    1.39%  (anon)
10)    1          14.29    14.29    1.54%     10.26    10.26    1.11%  nvm_die_on_prefix
11)    1           9.31     9.31    1.00%      9.31     9.31    1.00%  nvm_is_version_installed
12)  192           7.64     0.04    0.82%      7.45     0.04    0.80%  _zsh_autosuggest_bind_widget
13)    2           6.04     3.02    0.65%      6.04     3.02    0.65%  update_terminalapp_cwd
14)    1           5.87     5.87    0.63%      5.87     5.87    0.63%  nvm_supports_source_options
15)    1          13.21    13.21    1.43%      5.57     5.57    0.60%  _zsh_autosuggest_bind_widgets
16)    1           4.52     4.52    0.49%      4.52     4.52    0.49%  load_device_zsh_configuration
17)    1           3.83     3.83    0.41%      3.83     3.83    0.41%  nvm_grep
18)    3           1.17     0.39    0.13%      1.17     0.39    0.13%  up-line-or-beginning-search
19)    1           0.84     0.84    0.09%      0.84     0.84    0.09%  colors
20)    5           1.75     0.35    0.19%      0.53     0.11    0.06%  _zsh_autosuggest_invoke_original_widget
21)    4           2.11     0.53    0.23%      0.29     0.07    0.03%  _zsh_autosuggest_widget_clear
22)    4           0.24     0.06    0.03%      0.24     0.06    0.03%  add-zsh-hook
23)    1           0.23     0.23    0.02%      0.23     0.23    0.02%  update_terminal_cwd
24)    4           4.03     1.01    0.43%      0.20     0.05    0.02%  nvm_npmrc_bad_news_bears
25)    2           0.20     0.10    0.02%      0.20     0.10    0.02%  is-at-least
26)   15           0.19     0.01    0.02%      0.19     0.01    0.02%  _zsh_autosuggest_incr_bind_count
27)    3           1.98     0.66    0.21%      0.11     0.04    0.01%  _zsh_autosuggest_bound_2_up-line-or-beginning-search
28)    5           0.10     0.02    0.01%      0.10     0.02    0.01%  _zsh_autosuggest_highlight_reset
29)    5           0.09     0.02    0.01%      0.09     0.02    0.01%  _zsh_autosuggest_highlight_apply
30)    4           1.68     0.42    0.18%      0.08     0.02    0.01%  _zsh_autosuggest_clear
31)    1           0.31     0.31    0.03%      0.07     0.07    0.01%  _zsh_autosuggest_widget_accept
32)    1           0.06     0.06    0.01%      0.06     0.06    0.01%  nvm_has
33)    1          13.27    13.27    1.43%      0.06     0.06    0.01%  _zsh_autosuggest_start
34)    2           0.06     0.03    0.01%      0.06     0.03    0.01%  bashcompinit
35)    1         409.03   409.03   44.12%      0.06     0.06    0.01%  nvm_process_parameters
36)    1           0.12     0.12    0.01%      0.06     0.06    0.01%  complete
37)    3           0.05     0.02    0.01%      0.05     0.02    0.01%  is_theme
38)    1           0.20     0.20    0.02%      0.05     0.05    0.00%  _zsh_autosuggest_accept
39)    1           0.35     0.35    0.04%      0.04     0.04    0.00%  _zsh_autosuggest_bound_1_forward-char
40)    1           0.04     0.04    0.00%      0.04     0.04    0.00%  _zsh_autosuggest_orig_forward-char
41)    1           0.27     0.27    0.03%      0.03     0.03    0.00%  _zsh_autosuggest_bound_1_accept-line
42)    1           0.03     0.03    0.00%      0.03     0.03    0.00%  is_plugin
43)    1           0.03     0.03    0.00%      0.03     0.03    0.00%  omz_termsupport_precmd
44)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  zle-line-finish
45)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  _zsh_autosuggest_orig_accept-line
46)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  detect-clipboard
47)    2           0.02     0.01    0.00%      0.02     0.01    0.00%  env_default
48)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  omz_termsupport_preexec
49)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  zle-line-init
50)    1           0.01     0.01    0.00%      0.01     0.01    0.00%  nvm_is_zsh

-----------------------------------------------------------------------------------
...

從這里可以看出 nvm 用時占比還是很大的颤绕。此前我在 Oh My Zsh 的 plugins 加載了一遍 nvm 插件诅炉,加上原有的 nvm 加載配置,啟動耗時來到 1.6s 左右屋厘,就很離譜涕烧,是我用錯了。

四汗洒、解決 nvm 耗時問題

當(dāng)然议纯,影響 zsh 啟動用時的不僅僅有 nvm,具體因人而異溢谤。

我這里除了 Oh My Zsh 的一些東西(有空再收拾它)之外瞻凤,就屬 nvm 耗時最大了。

方案一(不推薦)

用 Google 搜索 Unable to resolve your shell environment in a reasonable time. 應(yīng)該很容易找到類似以下的解決方法:

.zshrc 中添加以下配置:

function load-nvm {
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"                   # This loads nvm
  [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
}

# nvm
if [[ "x${TERM_PROGRAM}" = "xvscode" ]]; then
  echo 'in vscode, nvm not work; use `load-nvm`'
else
  load-nvm
fi

思路很簡單世杀,利用環(huán)境變量 TERM_PROGRAM 判斷調(diào)用 Shell 的應(yīng)用程序阀参,如果是 VS Code 的話,就不加載 nvm瞻坝,以減少解析 Shell 的時間蛛壳,從而解決文章開頭的問題。

但從使用體驗上看所刀,有點傻衙荐,有點麻煩... 當(dāng)你使用 VS Code 內(nèi)置終端時,可以看到:

# 加載 .zshrc 的輸出內(nèi)容
in vscode, nvm not work; use `load-nvm`

# 執(zhí)行 nvm 命令出錯浮创,因為啟動當(dāng)前 Shell 時為加載 nvm忧吟,自然就找不到了
$ nvm current
zsh: correct 'nvm' to 'nm' [nyae]? n
zsh: command not found: nvm

# 手動加載 nvm(前面聲明的一個加載函數(shù))
$ load-nvm

# 再次執(zhí)行 nvm 命令
$ nvm current
v16.14.0

對于一個長時間使用 VS Code 的用戶來說,這是不能容忍的斩披,即使使用 nvm 的次數(shù)也是寥寥無幾溜族。

方案二

在 nvm 文檔中,可以發(fā)現(xiàn):

You can add --no-use to the end of the above script (...nvm.sh --no-use) to postpone using nvm until you manually use it.(詳見

也就是添加 --no-use 參數(shù)垦沉,以推遲使用 nvm煌抒。當(dāng)你在使用時才會加載。修改 nvm 相關(guān)配置乡话,如下:

# NVM
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" --no-use          # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

然后對比下摧玫,--no-use 添加前后 zsh 的啟動用時:

$ for i in $(seq 1 5); do /usr/bin/time /bin/zsh -i -c exit; done

        0.23 real         0.16 user         0.07 sys
        0.23 real         0.16 user         0.07 sys
        0.23 real         0.16 user         0.07 sys
        0.23 real         0.16 user         0.07 sys
        0.23 real         0.16 user         0.07 sys

從之前的 0.6s 多降低到 0.2s 多。最重要的是,它不會像方案一那樣诬像,還要手動執(zhí)行加載 nvm 的命令屋群。

方案三

聽說 nvm 相比其他 Node 版本解決方案,要慢很多坏挠∩瞩铮可選的解決方案有:

  • n:與 nvm 不同的是,它是一個 npm 包降狠,也就是依賴于 node对竣。而 nvm 是一個獨立的程序。
  • fnm:使用 rust 寫的榜配,是不是還沒用就感覺到快了否纬,哈哈。
  • nvs:這個沒了解過...
  • 更多請看...

關(guān)于 管理 node 版本蛋褥,選擇 nvm 還是 n临燃?

五、參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烙心,一起剝皮案震驚了整個濱河市膜廊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淫茵,老刑警劉巖爪瓜,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匙瘪,居然都是意外死亡铆铆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門辆苔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來算灸,“玉大人,你說我怎么就攤上這事驻啤。” “怎么了荐吵?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵骑冗,是天一觀的道長。 經(jīng)常有香客問我先煎,道長贼涩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任薯蝎,我火速辦了婚禮遥倦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己袒哥,他們只是感情好缩筛,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堡称,像睡著了一般瞎抛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上却紧,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天桐臊,我揣著相機與錄音,去河邊找鬼晓殊。 笑死断凶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巫俺。 我是一名探鬼主播认烁,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼识藤!你這毒婦竟也來了砚著?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤痴昧,失蹤者是張志新(化名)和其女友劉穎稽穆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赶撰,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡舌镶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了豪娜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片餐胀。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瘤载,靈堂內(nèi)的尸體忽然破棺而出否灾,到底是詐尸還是另有隱情,我是刑警寧澤鸣奔,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布墨技,位于F島的核電站,受9級特大地震影響挎狸,放射性物質(zhì)發(fā)生泄漏扣汪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一锨匆、第九天 我趴在偏房一處隱蔽的房頂上張望崭别。 院中可真熱鬧,春花似錦、人聲如沸茅主。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暗膜。三九已至匀奏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間学搜,已是汗流浹背娃善。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瑞佩,地道東北人聚磺。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像炬丸,于是被迫代替她去往敵國和親瘫寝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容