【问题标题】:Pypy (python) optimizationPypy (python) 优化
【发布时间】:2013-03-17 22:08:16
【问题描述】:

我正在考虑用 python 代码替换一些 C 代码并使用 pypy 作为解释器。该代码做了很多列表/字典操作。因此,为了对 pypy 与 C 的性能有一个模糊的了解,我正在编写排序算法。为了测试我所有的读取函数,我用 python 和 C++ 编写了一个冒泡排序。 CPython 当然是 6.468 秒,pypy 是 0.366 秒,C++ 是 0.229 秒。然后我记得我在C++代码上忘记了-O3,时间到了0.042s。对于带有 -O3 的 32768 数据集,C++ 只有 2.588 秒,而 pypy 是 19.65 秒。我可以做些什么来加快我的 python 代码(当然除了使用更好的排序算法)或我如何使用 pypy(一些标志或其他东西)?

Python 代码(read_nums 模块省略,因为它的时间很简单:0.036 秒在 32768 数据集上):

import read_nums
import sys

nums = read_nums.read_nums(sys.argv[1])

done = False

while not done:
    done = True

    for i in range(len(nums)-1):
        if nums[i] > nums[i+1]:
            nums[i], nums[i+1] = nums[i+1], nums[i]
            done = False

$ time pypy-c2.0 bubble_sort.py test_32768_1.nums   
real    0m20.199s
user    0m20.189s
sys     0m0.009s

C 代码(read_nums 函数再次省略,因为它需要很少的时间:0.017s):

#include <iostream>
#include "read_nums.h"

int main(int argc, char** argv)
{
    std::vector<int> nums;
    int count, i, tmp;
    bool done;

    if(argc < 2)
    {
        std::cout << "Usage: " << argv[0] << " filename" << std::endl;
        return 1;
    }

    count = read_nums(argv[1], nums);

    done = false;

    while(!done)
    {
        done = true;

        for(i=0; i<count-1; ++i)
        {
            if(nums[i] > nums[i+1])
            {
                tmp = nums[i];
                nums[i] = nums[i+1];
                nums[i+1] = tmp;
                done = false;
            }
        }
    }

    for(i=0; i<count; ++i)
    {
        std::cout << nums[i] << ", ";
    }

    return 0;
}

$ time ./bubble_sort test_32768_1.nums > /dev/null  
real    0m2.587s
user    0m2.586s
sys     0m0.001s

P.S.第一段中给出的一些数字与时间的数字略有不同,因为它们是我第一次得到的数字。

进一步改进:

  • 刚刚尝试使用 xrange 而不是 range,运行时间达到 16.370 秒。
  • 将函数中从第一个 done = False 开始的代码移动到最后一个 done = False,速度现在为 8.771-8.834s。

【问题讨论】:

  • 如果像在 c 代码中那样使用 tmp 变量会发生什么?
  • W/ xrange 需要 19.431 秒,w/ xrange 和 tmp 需要 19.760 秒。不知道为什么我的 xrange 倒退了这么多。
  • 好的,xrange no tmp 显然是一个异常值,我又运行了 5 次,它的范围是 16.385s-17.158s。使用 tmp 变量 5 倍,范围为 18.923s-19.444s。
  • 一个更好的问题可能是,为什么要将一些代码从 C 移动到 python?你在两者之间的接口有问题吗?通常人们用python编写,然后在需要速度时使用C。我还没有听说过从 C 到 python,尤其是当速度是一个问题时。
  • 我应该澄清一下,我不只是计划将 C 代码转换为 python 代码,而是在完成转换后添加大量代码。 C 代码很难理解,而且我不相信它的列表/字典数据结构有那么高效。此外,还有很多开发工作要做,我认为在 python 中的开发会比在 C 中更容易和更快。如果我能以 C 的 20-30% 的速度获得 pypy,那么我会没事的只是将代码留在 python 中。

标签: python bubble-sort pypy


【解决方案1】:

回答这个问题最相关的方法是注意 C、CPython 和 PyPy 的速度并没有恒定因素的差异:它最重要的是取决于所做的事情和编写的方式。例如,如果您的 C 代码正在执行诸如遍历数组之类的幼稚操作,而“等效”Python 代码自然会使用字典,那么只要数组足够长,Python 的任何实现都比 C 更快。当然,大多数现实生活中的例子并非如此,但同样的论点在较小程度上仍然适用。没有一种万能的方法来预测用 C 编写或用 Python 重写并在 CPython 或 PyPy 上运行的程序的相对速度。

显然有关于这些相对速度的指导方针:在小型算法示例中,您可以预期 PyPy 的速度接近“gcc -O0”的速度。在您的示例中,它“仅”慢了 1.6 倍。我们可能会帮助您优化它,甚至发现 PyPy 中缺少的优化,以便将速度提高 10% 或 30%。但这是一个与您的实际程序无关的小例子。由于上述原因,我们在这里得到的速度只是与你最终得到的速度有模糊的关系。

我只能说,为了清楚起见,将代码从 C 重写为 Python,特别是当 C 变得过于纠结而无法进一步开发时,从长远来看显然是一种胜利 --- 即使在最后,您需要再次用 C 重写其中的某些部分。 PyPy 的目标是减少对此的需求。虽然说再也没有人需要 C 会很好,但事实并非如此:-)

【讨论】:

  • 两件事:一,我想学习优化 PyPy 的技术(例如使用函数而不是全局做东西),二,显然我应该在 C 中使用正确的数据结构,但是例如,PyPy 的字典实现可能非常好,要获得类似的速度,在 C 语言中可能需要付出很多努力,在这种情况下,PyPy 会有优势。
猜你喜欢
  • 1970-01-01
  • 2013-06-25
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 2013-05-28
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多