我通过运行 10 亿次循环来测试 Bash 和 Python 的速度。
$ cat python.py
#!/bin/python
# python v3.5
i=0;
while i<=1000000000:
i=i+1;
重击代码:
$ cat bash2.sh
#!/bin/bash
# bash v4.3
i=0
while [[ $i -le 1000000000 ]]
do
let i++
done
使用该time
命令,我发现 Python 代码只需要 48 秒即可完成,而 Bash 代码则需要 1 个多小时才能杀死脚本。
为什么会这样呢?我预计 Bash 会更快。我的脚本有问题吗?还是 Bash 使用这个脚本真的慢很多?
答案1
Shell 循环很慢,bash 的循环最慢。 Shell 不适合在循环中执行繁重的工作。 Shell 旨在针对批量数据启动一些外部优化进程。
不管怎样,我很好奇 shell 循环如何比较,所以我做了一些基准测试:
#!/bin/bash
export IT=$((10**6))
echo POSIX:
for sh in dash bash ksh zsh; do
TIMEFORMAT="%RR %UU %SS $sh"
time $sh -c 'i=0; while [ "$IT" -gt "$i" ]; do i=$((i+1)); done'
done
echo C-LIKE:
for sh in bash ksh zsh; do
TIMEFORMAT="%RR %UU %SS $sh"
time $sh -c 'for ((i=0;i<IT;i++)); do :; done'
done
G=$((10**9))
TIMEFORMAT="%RR %UU %SS 1000*C"
echo 'int main(){ int i,sum; for(i=0;i<IT;i++) sum+=i; printf("%d\n", sum); return 0; }' |
gcc -include stdio.h -O3 -x c -DIT=$G -
time ./a.out
( 细节:
- CPU:Intel(R) Core(TM) i5 CPU M 430 @ 2.27GHz
- ksh:sh 版本(AT&T 研究)93u+ 2012-08-01
- bash:GNU bash,版本 4.3.11(1)-release (x86_64-pc-linux-gnu)
- zsh:zsh 5.2(x86_64-未知-linux-gnu)
- 破折号:0.5.7-4ubuntu1
)
(缩写)结果(每次迭代的时间)是:
POSIX:
5.8 µs dash
8.5 µs ksh
14.6 µs zsh
22.6 µs bash
C-LIKE:
2.7 µs ksh
5.8 µs zsh
11.7 µs bash
C:
0.4 ns C
从结果来看:
如果您想要稍微快一点的 shell 循环,那么如果您有语法[[
并且想要快速的 shell 循环,那么您就处于高级 shell 中,并且也有类似 C 的 for 循环。然后使用 C 语言的 for 循环。它们的速度大约是while [
同一 shell 中 -loops 的 2 倍。
- 克什最快的
for (
循环大约为2.7微秒每次迭代 - 短跑最快的
while [
循环大约为5.8微秒每次迭代
C for 循环可以快 3-4 个小数数量级。 (我听说 Torvalds 喜欢 C)。
优化后的 C for 循环比 bash 的while [
循环(最慢的 shell 循环)快 56500 倍,比 ksh 的for (
循环(最快的 shell 循环)快 6750 倍。
同样,shell 的速度慢应该没什么影响,因为 shell 的典型模式是将负载卸载到外部优化程序的几个进程。
通过这种模式,shell 通常可以更轻松地编写性能优于 python 脚本的脚本(我上次检查时,在 python 中创建流程管道相当笨拙)。
另一件需要考虑的事情是启动时间。
time python3 -c ' '
在我的 PC 上需要 30 到 40 毫秒,而 shell 大约需要 3 毫秒。如果您启动大量脚本,这个时间很快就会增加,并且您可以在 python 启动所需的额外 27-37 毫秒内完成非常多的事情。小脚本可以在这段时间内完成多次。
(NodeJs 可能是这个部门中最差的脚本运行时,因为它只需要大约 100 毫秒才能启动(即使一旦启动,您就很难在脚本语言中找到更好的性能))。
答案2
这是 bash 中的一个已知错误;请参阅手册页并搜索“BUGS”:
BUGS It's too big and too slow.
;)
要了解 shell 脚本与其他编程语言之间概念差异的优秀入门知识,我强烈建议阅读:
最相关的摘录:
shell 是一种高级语言。有人可能会说它甚至不是一种语言。它们位于所有命令行解释器之前。这项工作是由您运行的命令完成的,shell 只是为了编排它们。
...
IOW,在 shell 中,特别是在处理文本时,您调用尽可能少的实用程序并让它们配合任务,而不是按顺序运行数千个工具,等待每个工具启动、运行、清理,然后再运行下一个工具。
...
如前所述,运行一个命令是有成本的。如果该命令不是内置的,则成本巨大,但即使它们是内置的,成本也很大。
shell 并不是被设计成这样运行的,它们没有自称是高性能的编程语言。它们不是,它们只是命令行解释器。因此,在这方面几乎没有进行任何优化。
不要在 shell 脚本中使用大循环。
答案3
我做了一些测试,并在我的系统上运行了以下代码——没有一个能够达到具有竞争力所需的数量级加速,但你可以让它更快:
测试1:18.233s
#!/bin/bash
i=0
while [[ $i -le 4000000 ]]
do
let i++
done
测试2:20.45秒
#!/bin/bash
i=0
while [[ $i -le 4000000 ]]
do
i=$(($i+1))
done
测试3:17.64s
#!/bin/bash
i=0
while [[ $i -le 4000000 ]]; do let i++; done
测试4:26.69s
#!/bin/bash
i=0
while [ $i -le 4000000 ]; do let i++; done
测试5:12.79s
#!/bin/bash
export LC_ALL=C
for ((i=0; i != 4000000; i++)) {
:
}
最后一项中的重要部分是导出 LC_ALL=C。我发现如果使用它,许多 bash 操作最终会显着加快,特别是任何正则表达式函数。它还显示了使用 {} 和 : 作为无操作的未记录的语法。
答案4
答案:Bash 比 Python 慢得多。
博客文章中有一个小例子多种语言的性能。