Python Pypy写文件速度慢

Python Pypy写文件速度慢,python,file-io,pypy,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)]) 我看到PyPy的速度比普通Python慢了60倍

我最近一直在尝试使用PyPy,它比我当前的项目快了25倍,而且运行得非常好。然而不幸的是,编写文件的速度非常慢。写文件的速度大约慢60倍

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

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

with file(path, 'w') as f:
    f.writelines(['testing to write a file\n' for i in range(5000000)])
我看到PyPy的速度比普通Python慢了60倍。这将使用64位2.7.3和PyPy1.9、32位和Python 2.7.2。当然,两者都在同一操作系统和机器上(Windows 7)


任何帮助都将不胜感激。PyPy比我现在做的要快得多,但是由于文件写入速度限制在每秒半兆字节,它显然没有那么有用。

xrange
是这个示例的答案,正如它所列出的,但它是一个生成器。在生成包含5000万个项目的列表时,64位python可能比32位pypy更快


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

在这个系统上速度较慢,但不会慢60倍

TLDR;使用
write('\n'。连接(…)
代替
writeline(…)

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)

使用
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


让我们首先了解一下您的基准测试方法

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

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

但是,在您的情况下,动态数据生成可能比您的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的文件编写速度足以满足您的需要的条件

您在这里生成了两个列表,一个带有
范围
,另一个带有列表理解

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

您可以使用
–objspace std with range list
选项启用此功能

列表2:在编写输出列表之前,您正在创建输出列表。这也应该是一个生成器,因此将列表理解转换为生成器表达式:

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

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

RangeList默认为启用,range不会分配pypy上的所有内存。不过,这在这里完全无关紧要。PyPy docs直接声明默认情况下未启用此功能:对不起,您是对的,列出翻译信息表明它已启用。在linux上,这些速度时间非常相似。由于GC的原因,PyPy对我来说稍微慢了一点(20%)(不过有一个分支可以解决这些问题)。某种奇怪的窗户?你能把这些东西放在bugs.pypy.org上而不是放在这里吗?stackoverflow并不是一个很好的bug跟踪器的替代品。这根本不能解释观察结果,因为它至少对CPython和PyPy都是如此。使用
范围
,pypypy甚至可能会带来好处(与CPython相比),因为有些版本包括一个优化,除非需要,否则列表实际上不会具体化。(另请参见Matthew Trevor的答案和注释)当将数据作为连续块写入时,我在PyPy中获得了更好的性能:差异大约是4倍,而不是60倍。尽管如此,速度仍然显著放缓。我想我会远离writelines(),一次完成整个过程。我很清楚基准测试包括了创建虚拟数据所需的时间。然而,由于writelines()在PyPy中的编写速度非常慢,因此差异非常小。在生成具有列表理解的字符串列表并将其写出时,PyPy在文件写入上花费的时间是在数据生成上花费的时间的300多倍。我将试着写出块,看看是否更快。谢谢
with file(path, 'w') as f:
    f.writelines('xxxx\n' for _ in xrange(10**6))
with file(path, 'w') as f:
    for chunk in ('x'*99999 for _ in xrange(10**3)):
       f.write(chunk)
f.writelines('testing to write a file\n' for i in range(5000000))