command-not-found causes VERY long zsh startup times
vegerot opened this issue · comments
This is my zshrc
start=`gdate +%s.%N`
export ZSH="$HOME/.oh-my-zsh"
fpath=(/usr/local/share/zsh-completions /usr/local/share/zsh-completions/conda-zsh-completion $fpath)
source $ZSH/oh-my-zsh.sh
end=`gdate +%s.%N`
runtime=$( echo "$end - $start"|bc -l )
echo "$runtime seconds"
when I open zsh
the output is always around .118130000 seconds
Now when I try adding command-not found
:
start=`gdate +%s.%N`
export ZSH="$HOME/.oh-my-zsh"
fpath=(/usr/local/share/zsh-completions /usr/local/share/zsh-completions/conda-zsh-completion $fpath)
if brew command command-not-found-init > /dev/null; then
eval "$(brew command-not-found-init)";
fi
source $ZSH/oh-my-zsh.sh
end=`gdate +%s.%N`
runtime=$( echo "$end - $start"|bc -l )
echo "$runtime seconds"
Now when I open zsh
, the output is around 2.358168000 seconds
!
Clearly, this is unacceptable. What can be done to speed this up?
Can you confirm time brew command ls
or time brew help
give normal run times?
It’s also very slow on my machine but it’s due to Homebrew itself, as every brew
invocation appears to have a ~1.8s overhead.
@bfontaine as you said, there is an overhead from brew
.
/usr/local/Homebrew/Library/Homebrew/cmd/list.rb
brew command ls 0.64s user 0.62s system 94% cpu 1.340 total
However, the startup time increase in unacceptable for my (or anybody's) bashrc
. Would it be possible to run this asynchronously, or to cache the results, or something to make this more acceptable? I mean, this script doesn't even NEED to do anything during the shell startup, only when you run commands. Would it be possible to just have brew command-not-found-init
define from shell functions that only get executed when needed? This would save tons of time.
Of course, no matter how little brew command-not-found-init
does, if any brew
command has that startup overhead, it seems to be an intractable problem. Unless, of course, we could cache the functions, and update the instructions to something like
if [ -f "/usr/local/bin/cellar/..."]; then
source "/usr/local/bin/cellar/...";
fi
That file just containing a bunch of definitions and/or cached results. This would bypass having to run brew. Again, if it added just a bit of time I wouldn't complain. But I think MOST people would think adding an extra SECOND to their shell startup for some basic functionality would be a dealbreaker.
Yep, I agree on the overhead. I feel like it’s recent as I don’t remember having any slowness issue when I originally created the command.
In the end, all the Ruby command does is check your shell and dump the appropriate handler -- handler.sh
for Bash/Zsh or handler.fish
for Fish.
That shell part defines the command-not-found
hook and registers it for the current session. It can’t be asynchronous because it must run in the current shell.
I’m not on a Mac right now but something like this should feel instantaneous:
HB_CNF_HANDER="$(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh"
if [ -f "$HB_CNF_HANDER" ]; then
source "$HB_CNF_HANDER";
fi
brew --prefix
returns before Homebrew starts loading Ruby, so it doesn’t suffer from its performance issues.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
So should I/someone make a PR fixing this?
Yes, that would be great!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
I've been seeing slow startup times myself as well, in my case with Bash's .bash_profile. Is there a planned PR for this?
@andrewarchi I might work on a PR if I have some free time
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.