Pypy在写文件时很慢

时间:2012-09-25 13:36:40

标签: python file-io pypy

我最近一直在尝试使用PyPy,对于我目前的项目,它的速度提高了25倍,而且它运行得非常好。不幸的是,写文件令人难以置信慢。写文件的速度大约慢了60倍。

我一直在谷歌上搜索一下,但我没有找到任何有用的东西。这是一个已知的问题?有解决方法吗?

在这样一个简单的测试案例中:

with file(path, 'w') as f:
    f.writelines(['testing to write a file\n' for i in range(5000000)])

与常规Python相比,我发现PyPy的速度下降了60倍。这是使用64位2.7.3和PyPy 1.9,32位和Python 2.7.2。当然,两者都在相同的操作系统和机器上(Windows 7)。

任何帮助将不胜感激。 PyPy对于我正在做的事情来说要快得多,但是文件写入速度限制在每秒半兆字节,这显然不太有用。

4 个答案:

答案 0 :(得分:2)

速度较慢,但​​在此系统上速度不会慢60倍

TLDR;使用write('\n'.join(...))代替writelines(...)

$ pypy -m timeit -s "path='tst'" "with file(path, 'w') as f:f.writelines(['testing to write a file\n' for i in range(5000000)])"
10 loops, best of 3: 1.15 sec per loop

$ python -m timeit -s "path='tst'" "with file(path, 'w') as f:f.writelines(['testing to write a file\n' for i in range(5000000)])"
10 loops, best of 3: 434 msec per loop

xrange没有区别

$ pypy -m timeit -s "path='tst'" "with file(path, 'w') as f:f.writelines(['testing to write a file\n' for i in xrange(5000000)])"
10 loops, best of 3: 1.15 sec per loop

使用生成器表达式对于pypy来说比较慢,但对于python来说则更快

$ pypy -m timeit -s "path='tst'" "with file(path, 'w') as f:f.writelines('testing to write a file\n' for i in xrange(5000000))"
10 loops, best of 3: 1.62 sec per loop
$ python -m timeit -s "path='tst'" "with file(path, 'w') as f:f.writelines('testing to write a file\n' for i in xrange(5000000))"
10 loops, best of 3: 407 msec per loop

在基准之外移动数据创建会放大差异(~4.2x)

$ pypy -m timeit -s "path='tst'; data=['testing to write a file\n' for i in range(5000000)]" "with file(path, 'w') as f:f.writelines(data)"
10 loops, best of 3: 786 msec per loop
$ python -m timeit -s "path='tst'; data=['testing to write a file\n' for i in range(5000000)]" "with file(path, 'w') as f:f.writelines(data)"
10 loops, best of 3: 189 msec per loop

使用write()代替writelines()对两者来说都快得多。

$ pypy -m timeit -s "path='tst'; data='\n'.join('testing to write a file\n' for i in range(5000000))" "with file(path, 'w') as f:f.write(data)"
10 loops, best of 3: 51.9 msec per loop
$ python -m timeit -s "path='tst'; data='\n'.join('testing to write a file\n' for i in range(5000000))" "with file(path, 'w') as f:f.write(data)"
10 loops, best of 3: 52.4 msec per loop

$ uname -srvmpio
Linux 3.2.0-26-generic #41-Ubuntu SMP Thu Jun 14 17:49:24 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
$ python  --version
Python 2.7.3
$ pypy --version
Python 2.7.2 (1.8+dfsg-2, Feb 19 2012, 19:18:08)
[PyPy 1.8.0 with GCC 4.6.2]

答案 1 :(得分:0)

xrange是此示例的答案,因为它doesn't generate列表,但是生成器。在生成包含5000万个项目的列表时,64位python可能比32位pypy更快。

如果您有其他代码,请发布实际代码,而不仅仅是测试。

答案 2 :(得分:0)

让我们首先直接获得您的基准测试方法。

当目标是测量纯文件写入性能时,创建要在您正在计时的代码段中写入文件的数据是一个主要缺陷,系统性错误。那是因为数据创建也需要您不想测量的时间。

因此,如果您计划将整个虚拟数据保留在内存中,请在测量时间之前创建它。

但是,在您的情况下,动态数据生成可能比您的I / O更快。因此,通过使用Python生成器(在本例中为生成器表达式)与write调用相结合,您可以摆脱这种系统错误。

writelines相比,我不知道write的表现如何。但是,根据您的writelines示例:

with file(path, 'w') as f:
    f.writelines('xxxx\n' for _ in xrange(10**6))

使用write编写大块数据可能会更快:

with file(path, 'w') as f:
    for chunk in ('x'*99999 for _ in xrange(10**3)):
       f.write(chunk)

当你获得正确的基准测试时,我很确定你会发现Python和PyPy之间存在差异。在某些情况下,PyPy甚至可能显着变慢。但是,通过适当的基准测试,我相信您将设法找到PyPy文件编写速度足够快的条件。

答案 3 :(得分:-1)

您在此处生成了两个列表,其中一个包含range,另一个包含列表推导。

列表1:一个选项是用生成器range替换返回xrange的列表。另一种方法是尝试PyPy自己的优化,称为range-lists

  

您可以使用–objspace-std-withrangelist选项启用此功能。

列表2:您在编写之前创建输出列表。这也应该是一个生成器,所以将列表推导转换为生成器表达式:

f.writelines('testing to write a file\n' for i in range(5000000))

只要生成器表达式是传递给函数的唯一参数,就不需要在括号上加倍。