为什么在C#中我的计算比Python这么快

问题描述:

下面是分别用 C# Python 编码的一个简单过程(对于那些对此过程感到好奇的人,这是欧拉计划).

Below is a simple piece of process coded in C# and Python respectively (for those of you curious about the process, it's the solution for Problem No. 5 of Project Euler).

我的问题是,下面的 C#代码仅花费9秒进行迭代,而 Python 代码的完成则需要283秒(确切地说,在Python 3.4上是283秒.3-64位和329秒(在Python 2.7.9-32位上).

My question is, the C# code below takes only 9 seconds to iterate, while completion of Python code takes 283 seconds (to be exact, 283 seconds on Python 3.4.3 - 64 bits and 329 seconds on Python 2.7.9 - 32 bits).

到目前为止,我已经在 C# Python 中编码了相似的过程,并且执行时间的差异是可比的.但是这次,经过的时间之间存在极大的差异.

So far, I've coded similar processes both in C# and Python and the execution time differences were comparable. This time however, there is an extreme difference between the elapsed times.

我认为,这种差异的一部分来自python语言的灵活变量类型(我怀疑python将一部分变量转换为double),但这仍然很难解释.

I think, some part of this difference arise from the flexible variable type of python language (I suspect, python converts some part of variables into double) but this much is still hard to explain.

我在做什么错了?

我的系统:Windows-7 64位,

My system: Windows-7 64 bits,

C#-VS Express 2012(9秒)

C# - VS Express 2012 (9 seconds)

Python 3.4.3 64位(283秒)

Python 3.4.3 64 bits (283 seconds)

Python 2.7.9 32位(329秒)

Python 2.7.9 32 bits (329 seconds)

c-sharp代码:

c-sharp code:

using System;

namespace bug_vcs {
    class Program {
        public static void Main(string[] args) {
            DateTime t0 = DateTime.Now;
            int maxNumber = 20;
            bool found = false;
            long start = maxNumber;
            while (!found) {
                found = true;
                int i = 2;
                while ((i < maxNumber + 1) && found) {
                    if (start % i != 0) {
                        found = false;
                    }
                    i++;
                }
                start++;
            }
            Console.WriteLine("{0:d}", start - 1);
            Console.WriteLine("time elapsed = {0:f} sec.", (DateTime.Now - t0).Seconds);
            Console.ReadLine();
        }
    }
}

和python代码:

from datetime import datetime

t0 = datetime.now()
max_number = 20
found = False
start = max_number
while not found:
    found = True
    i = 2
    while ((i < max_number + 1) and found):
        if (start % i) != 0:
            found = False
        i += 1
    start += 1

print("number {0:d}\n".format(start - 1))

print("time elapsed = {0:f} sec.\n".format((datetime.now() - t0).seconds))

答案很简单,就是Python处理所有对象的对象,并且没有

The answer is simply that Python deals with objects for everything and that it doesn't have JIT by default. So rather than being very efficient by modifying a few bytes on the stack and optimizing the hot parts of the code (i.e., the iteration) – Python chugs along with rich objects representing numbers and no on-the-fly optimizations.

如果您在具有JIT的Python变体(例如PyPy)中尝试过此操作,我保证您会看到很大的不同.

If you tried this in a variant of Python that has JIT (for example, PyPy) I guarantee you that you'll see a massive difference.

一个一般性提示是避免使用标准Python进行非常昂贵的操作(特别是如果这是针对后端处理来自多个客户端的请求).带有JIT的Java,C#,JavaScript等的效率无与伦比.

A general tip is to avoid standard Python for very computationally expensive operations (especially if this is for a backend serving requests from multiple clients). Java, C#, JavaScript, etc. with JIT are incomparably more efficient.

顺便说一句,如果您想以更Python的方式编写示例,可以这样做:

By the way, if you want to write your example in a more Pythonic manner, you could do it like this:

from datetime import datetime
start_time = datetime.now()

max_number = 20
x = max_number
while True:
    i = 2
    while i <= max_number:
        if x % i: break
        i += 1
    else:
        # x was not divisible by 2...20
        break
    x += 1

print('number:       %d' % x)
print('time elapsed: %d seconds' % (datetime.now() - start_time).seconds)

上面的代码在90秒内对我执行了.它之所以更快,是因为看似愚蠢的东西,例如 x start 短,我没有经常分配变量,而是依靠Python自己的控件结构而不是变量检查来跳入/跳出循环.

The above executed in 90 seconds for me. The reason it's faster relies on seemingly stupid things like x being shorter than start, that I'm not assigning variables as often, and that I'm relying on Python's own control structures rather than variable checking to jump in/out of loops.