在cygwin中缓慢加载bash的时间

For*_*ker 18 debugging bash cygwin bash-completion

目前bash需要大约2秒才能加载.我用-x旗帜运行bash,我看到输出,似乎PATH在cygwin中被多次加载.有趣的是我在linux环境中使用相同的文件,但它工作正常,没有重载问题.以下可能导致问题吗?

if [ `uname -o` = "Cygwin" ]; then
    ....
fi
Run Code Online (Sandbox Code Playgroud)

me_*_*and 21

正如您在答案中所提到的,问题是Cygwin的bash-completion包.快速简便的解决方法是禁用bash-completion,正确的方法是运行Cygwin的setup.exe(如果需要,再次下载)并选择卸载该软件包.

更长的解决方案是处理文件/etc/bash_completion.d并禁用您不需要的文件.在我的系统上,减慢Bash加载时间的最大罪魁祸首(mailman,shadow,dsniff和e2fsprogs)都没有做任何事情,因为他们创建完成的工具没有安装.

如果您将文件重命名/etc/bash_completion.d为具有.bak扩展名,则会停止加载该脚本.除了以这种方式在我的一个系统上禁用了所有37个脚本之外,我已经将bash_completion的平均加载时间减少了95%(6.5秒到0.3秒).


npe*_*npe 14

在我的情况下,这是Windows域控制器.我这样做是为了找到问题:

我从一个简单的Windows开始cmd.exe,输入:
c:\cygwin\bin\strace.exe c:\cygwin\bin\bash

就我而言,我注意到以下顺序:

    218   12134 [main] bash 11304 transport_layer_pipes::connect: Try to connect to named pipe: \\.\pipe\cygwin-c5e39b7a9d22bafb-lpc
     45   12179 [main] bash 11304 transport_layer_pipes::connect: Error opening the pipe (2)
     39   12218 [main] bash 11304 client_request::make_request: cygserver un-available
1404719 1416937 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#1>
    495 1417432 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#2>
    380 1417812 [main] bash 11304 pwdgrp::fetch_account_from_windows: line: <CENSORED_GROUP_ID_#3>

    etc...
Run Code Online (Sandbox Code Playgroud)

关键是确定client_request::make_request: cygserver un-available线.你可以看到,在此之后,cygwin试图从windows中获取每个组,并且执行时间变得疯狂.

快速谷歌透露了什么cygserver是:https: //cygwin.com/cygwin-ug-net/using-cygserver.html

Cygserver是一个旨在作为后台服务运行的程序.它为Cygwin应用程序提供了需要安全仲裁的服务,或者在没有其他cygwin应用程序运行时需要持久保存的服务.

解决方案是,运行cygserver-config然后net start cygserver启动Windows服务.之后,Cygwin的启动时间显着下降.


Gen*_*sky 5

所有答案都指向较旧的bash_completion版本,与最新版本无关bash_completion

Modern bash_completion默认将大多数完成文件移动到/usr/share/bash-completion/completions,通过运行以下命令检查系统上的路径

# pkg-config --variable=completionsdir bash-completion
/usr/share/bash-completion/completions
Run Code Online (Sandbox Code Playgroud)

那里有很多文件,每个命令一个文件,但这不是问题,因为它们是在您第一次对每个命令使用完成时按需加载的。/etc/bash_completion.d仍然支持旧版本的兼容性,并且bash_completion启动时会加载旧版本中的所有文件。

# pkg-config --variable=compatdir bash-completion
/etc/bash_completion.d
Run Code Online (Sandbox Code Playgroud)

使用此脚本检查旧目录中是否还有任何过时的文件。

#!/bin/sh
COMPLETIONS_DIR="$(pkg-config --variable=completionsdir bash-completion)"
COMPAT_DIR="$(pkg-config --variable=compatdir bash-completion)"
for file in "${COMPLETIONS_DIR}"/*; do
    file="${COMPAT_DIR}/${file#${COMPLETIONS_DIR}/}"
    [ -f "$file" ] && printf '%s\n' $file
done
Run Code Online (Sandbox Code Playgroud)

它打印compat目录中的文件列表,这些文件也存在于较新的(按需)完成目录中。除非有特殊原因要保留其中一些文件,否则请查看,备份并删除所有这些文件。

结果,compat目录应该大部分为空。

现在,对于最有趣的部分-检查bash启动缓慢的原因。如果您只是运行bash,它将启动一个非登录的交互式外壳程序-该程序在Cygwin源代码上/etc/bash.bashrc,然后在~/.bashrc。这很可能不包括bash补全,除非您从rc文件之一中获取它。如果你运行bash -lbash --login),启动Cygwin Terminal(取决于你cygwin.bat),或登录通过SSH,就会启动一个登录,互动的外壳-这将输出/etc/profile~/.bash_profile和上述RC文件。该/etc/profile脚本本身将提供中的所有可执行.sh文件/etc/profile.d

您可以检查每个文件花费多长时间。在/etc/profile以下位置找到此代码:

for file in /etc/profile.d/*.$1; do
  [ -e "${file}" ] && . "${file}"
done
Run Code Online (Sandbox Code Playgroud)

备份它,然后替换为:

for file in /etc/profile.d/*.$1; do
  TIMEFORMAT="%3lR ${file}"
  [ -e "${file}" ] && time . "${file}"
done
Run Code Online (Sandbox Code Playgroud)

单击开始bash,您将看到每个文件花费了多长时间。调查花费大量时间的文件。就我而言,它是bash_completion.shfzf.sh(fzf是模糊查找器,是对bash_completion的非常好的补充)。现在的选择是禁用它或进一步调查。由于我想继续fzf在bash中使用快捷方式,因此我进行了调查,找到了减速的源头,对其进行了优化,然后将补丁提交给了fzf的仓库(希望它会被接受)。

现在是最大的花费时间- bash_completion.sh。基本上就是脚本源/usr/share/bash-completion/bash_completion。我备份了该文件,然后对其进行了编辑。在最后一页上,存在for循环,该循环在compatdir-中提供所有文件/etc/bash_completion.d。再次,我添加了TIMEFORMATtime,然后查看是哪个脚本导致启动缓慢。是zzz-fzffzf包)。我进行了调查,发现一个子shell($())在一个for循环中被执行了多次,无需使用子shell就重写了该部分,从而使脚本可以快速工作。我已经将补丁提交给fzf的仓库。

所有这些速度下降的最大原因是:forkWindows进程模型不支持Cygwin在模拟它方面做得很好,但是与真正的UNIX相比,它的速度非常慢。仅执行很少工作的子外壳程序或管道就将其大部分执行时间用于fork-ing。例如,比较time echo msg(Cygwin上的0.000s)和time echo $(echo msg)(Cygwin上的0.042s )的执行时间-日夜。的echo命令本身不需要花费很多时间来执行,但是创建子外壳非常昂贵。在我的Linux系统上,这些命令分别花费0.000s和0.001s。Cygwin的许多软件包都是由使用Linux或其他UNIX的人开发的,并且可以在未经修改的Cygwin上运行。因此,这些开发人员自然会在方便的地方随意使用子shell,管道和其他功能,因为他们不会觉得系统性能有任何显着降低,但是在Cygwin上,这些shell脚本的运行速度可能慢几十倍甚至数百倍。

底线是,如果Shell脚本在Cygwin中运行缓慢,请尝试查找fork调用源并重写脚本以尽可能消除它们。例如cmd="$(printf "$1" "$2")"(用一个前叉作为子壳)可以替换为printf -v cmd "$1" "$2"

男孩,它出来的时间很长。仍然在这里读书的任何人都是真正的英雄。谢谢 :)