Repository: xonsh/xonsh

Issue:
Slower start: read files from PATH dirs many times
Hi! xonsh is shell but python but shell but python but the best!

While I worked on #3911 I found that reading of the files in the PATH directories was done many times in case of using default conda init:

```bash
pip install -U git+https://github.com/anki-code/xonsh.git@wsl_speed

# Run without rc - 1 warning
XONSH_WARNING_PATH_FILES=10 xonsh --no-rc
#Warning! Found 5,785 executable files in the PATH directories!
```
```bash
cat ~/.xonshrc_conda
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
import sys as _sys
from types import ModuleType as _ModuleType
_mod = _ModuleType("xontrib.conda",
                   "Autogenerated from $(/opt/miniconda/bin/conda shell.xonsh hook)")
__xonsh__.execer.exec($("/opt/miniconda/bin/conda" "shell.xonsh" "hook"),
                      glbs=_mod.__dict__,
                      filename="$(/opt/miniconda/bin/conda shell.xonsh hook)")
_sys.modules["xontrib.conda"] = _mod
del _sys, _mod, _ModuleType
# <<< conda initialize <<<
```
```bash
# Run with conda rc - 3 warnings
XONSH_WARNING_PATH_FILES=10 xonsh --rc ~/.xonshrc_conda 
#Warning! Found 5,785 executable files in the PATH directories!
#Warning! Found 5,785 executable files in the PATH directories!
#Warning! Found 5,785 executable files in the PATH directories!
```

**As result instead of scan 5795 - 2298 - 420 = 3077 files once it scans 5795 files 3 times = 17,385 in sum.**
It looks like this is the cause why xonsh have 2 sec start time on my linux!

Please take a look at `commands_cache.py` and conda init. It looks like a speed issue.

Also `--timings` not shows the time of creating prompt on the first run that uses commands_cache so this is why no one can detect the problem.

## For community
⬇️  **Please click the 👍 reaction instead of leaving a `+1` or 👍  comment**



Discussion:
> As result instead of scan 5795-2298-420=3077 files once it scans 5795 files 3 times = 17,385 in sum.

@scopatz and the counter here the source of truth instead of `len(allcmds)`;)
The counter is too slow in my opinion. 

Resolving patch:
diff --git a/xonsh/commands_cache.py b/xonsh/commands_cache.py
--- a/xonsh/commands_cache.py
+++ b/xonsh/commands_cache.py
@@ -83,12 +83,12 @@ def all_commands(self):
         path_immut = tuple(x for x in paths if os.path.isdir(x))
         # did PATH change?
         path_hash = hash(path_immut)
-        cache_valid = path_hash == self._path_checksum
+        cache_valid_path = path_hash == self._path_checksum
         self._path_checksum = path_hash
         # did aliases change?
         alss = getattr(builtins, "aliases", dict())
         al_hash = hash(frozenset(alss))
-        cache_valid = cache_valid and al_hash == self._alias_checksum
+        cache_valid_aliases = al_hash == self._alias_checksum
         self._alias_checksum = al_hash
         # did the contents of any directory in PATH change?
         max_mtime = 0
@@ -96,10 +96,19 @@ def all_commands(self):
             mtime = os.stat(path).st_mtime
             if mtime > max_mtime:
                 max_mtime = mtime
-        cache_valid = cache_valid and (max_mtime <= self._path_mtime)
+        cache_valid_paths = max_mtime <= self._path_mtime
         self._path_mtime = max_mtime
-        if cache_valid:
+
+        if cache_valid_path and cache_valid_paths:
+            if not cache_valid_aliases:
+                for cmd, alias in alss.items():
+                    key = cmd.upper() if ON_WINDOWS else cmd
+                    if key in self._cmds_cache:
+                        self._cmds_cache[key] = (self._cmds_cache[key][0], alias)
+                    else:
+                        self._cmds_cache[key] = (cmd, True)
             return self._cmds_cache
+
         allcmds = {}
         for path in reversed(path_immut):
             # iterate backwards so that entries at the front of PATH overwrite
@@ -121,6 +130,7 @@ def all_commands(self):
             if cmd not in allcmds:
                 key = cmd.upper() if ON_WINDOWS else cmd
                 allcmds[key] = (cmd, True)
+
         self._cmds_cache = allcmds
         return allcmds
 


Test patch: