【问题标题】:Speed difference in Python compiled with MS C vs. MinGW使用 MS C 与 MinGW 编译的 Python 的速度差异
【发布时间】:2014-09-17 13:14:32
【问题描述】:

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

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

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

我已尝试使用 MinGW 构建的版本为 Python 编译一些 C 扩展,这些扩展需要使用与 Python 本身相同的编译器构建才能正常运行。
现在考虑以下测试脚本,它会生成一个随机字典并反复腌制和取消腌制它。

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 扩展),但我很惊讶。
这是意料之中的事吗?
其他 C 扩展在 Python/MinGW 工具链上的运行速度一般会变慢吗?

【问题讨论】:

    标签: python c windows gcc mingw-w64


    【解决方案1】:

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

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

    更新

    我在 MSYS2 上尝试了您的示例程序。有两个可用的 Python 2.7 版本:一个是 MSYS2 发行版的一部分,另一个是 MinGW-w64 工具链的一部分。 MSYS2 包含的版本没有出现性能问题,而 MinGW-w64 包含的版本确实出现了 cPickle 的性能问题。由于MSYS2版本是由MinGW-w64中包含的GCC编译的,所以我相信速度慢与编译MinGW版本时使用的具体选项有关。我还没有查看这两个版本的源代码以了解导致差异的原因。

    关于使用与 Python 解释器相同版本的编译器进行扩展的要求 - 答案是“这取决于....”。出现此问题的原因是每个主要版本的 MSC 使用的 C 运行时库之间存在一些细微差异。 IIRC,其中一个差异可能会破坏 Python 和扩展之间的文件句柄传递。如果您不使用任何依赖于差异的调用,那么您可以混合编译器版本。由于没有明确的差异列表,也没有阻止扩展程序发出不同调用的方法,因此唯一可以保证的答案是不混合版本。我的扩展不(我认为)使用任何不同的 C 运行时调用。它仅使用 Python C-API 进行所有 IO 和内存管理。我在测试时已经成功混合了编译器版本,但我还是不想这样做。

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

    【讨论】:

    • python.org 的版本都是 AFAIK,都是用 MSC 编译的。所以你没有使用用 MinGW 编译的 CPython 版本,对吧?这不会与上述结果相矛盾。为 Python 使用与扩展不同的编译器从来都不是问题吗?
    • @Pybe 我已经扩展了我的答案。
    • 你是对的! MSYS2 版本是最新的。谢谢你指点我那里。
    猜你喜欢
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 2012-06-01
    相关资源
    最近更新 更多