从脚本语言中调用shell命令会降低性能吗?

时间:2013-03-07 22:00:51

标签: php python ruby perl shell

编写python,perl,ruby或php时 我会经常使用......

PERL:
`[SHELL COMMAND HERE]`
system("[SHELL]", "[COMMAND]", "[HERE]")

Python
import os
os.system("[SHELL COMMAND HERE]")
from subprocess import call
call("[SHELL]", "[COMMAND]", "[HERE]")

ruby 
`[SHELL COMMAND HERE]`
system("[SHELL COMMAND HERE]")

PHP
shell_exec ( "SHELL COMMAND HERE" )

在shell中生成子进程多少会降低程序的性能? 例如,我只是用perl和libcurl编写一个脚本,并且使用所有libcurl的参数很难让它工作。我停止使用libcurl并且刚开始使用curl并且性能似乎改进了,脚本变得更加容易,而且,我可以在只有基本perl(没有cpan模块)和基本shell实用程序的系统上运行我的脚本安装。

为什么产生这个子shell被认为是错误的编程习惯?从理论上讲,它应该比在语言中使用特定的绑定/等效库慢得多吗?

3 个答案:

答案 0 :(得分:6)

执行shell命令的第一个原因是可维护性。没有语言切换,任务之间的上下文切换就足够糟糕安全性也是一个考虑因素,但编码实践会使其不太重要(避免注射......)

有几个因素会影响效果:

  1. 分叉一个进程:这需要一段时间,但是如果正在执行的代码运行良好,这就不那么重要了。
  2. 优化变得不可能:当控件移交给另一个进程时,解释器或编译器无法执行任何优化。此外,您无法执行任何优化。
  3. 阻止:Shell命令是阻塞操作。它们不会像代码的原生部分那样被安排。
  4. 解析:如果需要对输出做些什么,则需要对其进行解析。在本机代码中,数据已经存在于相关的数据结构中。解析也容易出错。
  5. 命令行生成:为可执行文件生成命令行可能需要迭代。有时这比本地执行相同的周期需要更多的周期。
  6. 当外部命令在循环中执行时,会出现大多数这些问题。可能很容易找到这些都不成问题的例子。

答案 1 :(得分:4)

Ferrix很好地陈述了一些与性能相关的问题。

关于安全性和可维护性,我将提交以下内容:

  1. 可移植性/与外部依赖关系隔离

    • 当然,你可以打电话给wget - 如果你在Linux上。在Windows或Mac上,它会死得很厉害,您要么向老板解释为什么必须重新编写它以使用内置方法,或者支持需要使用的用户/同事你的工具(两者都不是很有趣)。

    • 有一天,你会花费数小时试图找出你的脚本不再有效的原因,但却发现外部程序的升级版本需要不同的命令行参数,而不再像你的代码所期望的那样工作。

  2. 一种语言中的转义字符(Pe​​rl / Python / PHP)不一定映射到shell语言中的转义字符(例如:SQL注入攻击可以说是一种语言中非转义字符的结果(HTML)与不同语言(SQL)混合使用。)

  3. 调试在一种语言中已经足够困难了 - 尝试调试为另一种语言生成命令的命令更加困难(特别是在转义引号时,很容易找到像{{1}这样的字符串} ...)

答案 2 :(得分:2)

谁说产生shell进程是不好的做法?当心教条主义者。没有严格的规则可以定义何时执行或不执行此操作。在您的示例中,当您开始进行卷曲时,您可以更快地完成项目并获得更好的性能。 证据总是在布丁中。

就性能而言,分叉(和执行)一个新的过程会导致命中,所以你应该避免它用于短时间的操作。但是如果子进程运行几秒钟,你就不会注意到它需要25ms(只是一个占位符#)。但是如果有一个非常快速运行的瞬态函数,那么你经常调用它,通过子shell调用它会导致显着的性能损失。

关于子进程的一件事是它们可以从命令行独立测试。所以它们实际上是独立的工具,这对于某些问题非常有用。

最后要考虑的事情。如果你相信“工作的正确工具”,并且正确的工具恰好已经在盒子上,并且你可以通过炮轰来解决手头的任务,那么为什么不呢?我在生活中看到了很多代码,这些代码最终无关紧要,因为问题已经通过一些免费提供(并且已经安装)的工具得以解决。它恰好不适合程序员选择的单片(读取单工具)实现环境。