使用MS C与MinGW编译的Python速度差异

时间:2014-09-17 13:14:33

标签: python c windows gcc mingw-w64

在我的Windows 7机器上,我使用了两个CPython实现:

1)WinPython distribution,使用MSC v.1500 64bit编译

2)MinGW-builds,使用MinGW / GCC 4.9.1 64位编译

我已经尝试使用MinGW构建的版本来编译Python的一些C扩展,这些扩展需要使用与Python本身相同的编译器来构建才能正常运行。
现在考虑以下测试脚本,它生成一个随机字典并重复pickle& unpickles it。

import pickle, cPickle, random
from time import clock

def timeit(mdl, d, num=100, bestof=10):
    times = []
    for _ in range(bestof):
        start = clock()
        for _ in range(num):
            mdl.loads(mdl.dumps(d))
        times.append(clock() - start)
    return min(times)

def gen_dict(entries=100, keylength=5):
    formatstr = "{:0%dx}" % keylength
    d = {}
    for _ in range(entries):
        rn = random.randrange(16**keylength) # 'keylength'-digit hex number
        # format into string of length 5 as key, decimal value as value
        d[formatstr.format(rn)] = rn
    return d

def main(entries=100, keylength=5, num=100, bestof=10):
    print "Dict size: %d entries, keylength: %d" % (entries, keylength)
    print ("Test is %d times pack/unpack. "
           "Take best time out of %d runs\n" % (num, bestof))
    d = gen_dict(entries, keylength)
    for mdl in [pickle, cPickle]:
        print "%s: %f s" % (mdl.__name__, timeit(mdl, d, num, bestof))

if __name__ == "__main__":
    main()
MSC CPython给了我

Dict size: 100 entries, keylength: 5
Test is 100 times pack/unpack. Take best time out of 10 runs

pickle: 0.107798 s
cPickle: 0.011802 s

和MinGW / GCC CPython给了我

Dict size: 100 entries, keylength: 5
Test is 100 times pack/unpack. Take best time out of 10 runs

pickle: 0.103065 s
cPickle: 0.075507 s

所以cPickle模块(Python的标准库C扩展)在MinGW上比在MSC上慢6.4倍。
我还没有进一步调查(即测试更多的C扩展),但我很惊讶 这是预期的吗?
在Python / MinGW工具链上,其他C扩展一般会运行得慢吗?

1 个答案:

答案 0 :(得分:0)

我使用MSYS2和MinGW-w64工具链来编译一个大的CPU绑定扩展。它并没有异常缓慢地运行;我实际上认为它比MSC运行得更快。扩展速度缓慢的一个可能原因:文件Mingw32CCompiler中包含的cygwincompiler.py类指定了-O优化。我将其更改为-O2,性能得到了改善。

我使用从python.org发布的标准CPython扩展。

<强>更新

我在MSYS2上尝试了你的示例程序。有两个版本的Python 2.7可用:一个是MSYS2发行版的一部分,另一个是MinGW-w64工具链的一部分。 MSYS2附带的版本不会出现性能问题,而MinGW-w64附带的版本确实会出现cPickle的性能问题。由于MSYS2版本是由MinGW-w64中包含的GCC编译的,我认为减速与编译MinGW版本时使用的特定选项有关。我没有查看两个版本的源代码,看看是什么导致了差异。

关于为扩展使用相同版本的编译器作为Python解释器的要求 - 答案是&#34;它取决于......&#34;。出现此问题是因为每个主要版本的MSC使用的C运行时库之间存在一些细微差别。 IIRC,其中一个差异可以打破Python和扩展之间的文件句柄传递。如果您不使用任何依赖于差异的调用,那么您可以混合使用编译器版本。由于没有明确的差异列表,也没有办法阻止扩展使这些不同的呼叫,唯一保证的答案不是混合版本。我的扩展没有(我认为)使用任何不同的C运行时调用。它仅将Python C-API用于所有IO和内存管理。我在测试时成功混合了编译器版本,但我仍然不愿意这样做。

我还在尝试使用MSYS2 / MinGW-w64方法来构建我的扩展,并将其与MSC编译的CPython版本一起使用。它确实有效,并且按预期执行。

相关问题