为什么在Python中运行100亿次迭代的大型for循环比在C中花费更长的时间?

时间:2018-09-29 16:12:47

标签: python c python-3.x

我目前正在比较Python3和C中的两个循环计算。对于Python,我有:

# Python3
t1 = time.process_time()
a = 100234555
b = 22333335
c = 341500
for i in range(1, 10000000001):
    a = a - (b % 2)
    b = b - (c % 2)
print("Sum is", a+b)
t2 = time.process_time()
print(t2-t1, "Seconds")

然后在C中,我做同样的事情:

#include <stdio.h>

int main() {
   long long a = 100234555;
   long long b = 22333335;  
   long long c = 341500;
   for(long long i = 1; i <= 10000000000; i++){
        a = a - (b % 2);
        b = b - (c % 2);
   }
   printf("Sum is %lld\n", a+b);
   return 0;
}

我在Python和C中都对代码计时。Python的时间约为3500秒,而C(包括编译和执行)的时间仅约0.3秒。

我想知道时间安排有多么大的差异。该执行是在具有100 GB Ram和足够处理能力的服务器上完成的。

3 个答案:

答案 0 :(得分:15)

部分原因是Python字节码是由程序而不是直接由CPU执行的,但是大部分开销是由于整数的不可变性而导致的内存分配和释放,这是由于对象模型引起的,而不是解释性。

这是怎么回事,您的C代码可以更改数字的值,但是在Python中数字是不可变的,这意味着它们不会更改。这意味着在进行求和时,Python必须为每个新值创建一个新的int对象,然后在不再使用旧的int之后销毁它们。这比仅修改单个内存值要慢得多。


您的C编译器也可能很聪明,原因是通过一连串的优化,它可以完全删除您的for循环,结果将是相同的-就像循环实际上在运行一样。我希望代码的运行速度比示例中的运行速度要快得多,但是它可以做到。

Python没有这样的智能编译器。它不能做那么宏伟的事情。它并不是为了优化代码而设计的,因为在动态类型的语言中很难可靠地做到这一点(尽管Python是强类型的事实确实使它具有某种可能性。

答案 1 :(得分:8)

正如dmuir所注意到的,如果编译器正确传播某些常量,则可以大大简化代码。例如:struct将C代码编译为此(cf https://gcc.godbolt.org/z/1ZH8Rm):

clang -O1

main: # @main push rax movabs rsi, -9877432110 mov edi, offset .L.str xor eax, eax call printf xor eax, eax pop rcx ret .L.str: .asciz "Sum is %lld\n" 产生基本上相似的代码。

由于这归结为对gcc -O1的单个调用,因此解释似乎是:

  • Python编译器不如C编译器来优化此代码。
  • 您的C编译器需要很长时间才能编译这12行代码。鉴于您的硬件设置,3秒太长了!在我的dinky笔记本电脑上,只需花费0.15秒即可编译和运行所有优化代码。您正在编译为C ++吗?

在禁用优化功能(printf)的情况下测试C版本会产生以下输出:

-O0

未优化的C仍然比Python快得多:255秒vs:> 3500

Python代码使用字节码和具有动态类型值的堆栈来解释:典型的减速是10到20。此外,对于较大的值,整数算法会自动切换到bignum模式,在这种情况下可能会发生这种情况,尽管代价会更高。

答案 2 :(得分:0)

答案很简单。 Python是解释性语言。所有指令均由解释器(执行脚本的特殊程序)执行。它比编译为本机代码的C代码要慢得多。