【问题标题】:Real file objects slower than StringIO and cStringIO?比 StringIO 和 cStringIO 慢的真实文件对象?
【发布时间】:2016-05-13 02:53:30
【问题描述】:

StringIO在其代码中有如下注释:

Notes:
- Using a real file is often faster (but less convenient).
- There's also a much faster implementation in C, called cStringIO, but
  it's not subclassable.

“真实文件通常更快”这句话对我来说似乎很奇怪:写入磁盘怎么能胜过写入内存?我尝试分析这些不同的案例并得到与这些文档相矛盾的结果,以及this question 的答案。 This other question 确实解释了为什么 cStringIO 在某些情况下速度较慢,尽管我在这里没有进行任何连接。测试将给定数量的数据写入文件,然后寻找开头并将其读回。在“新”测试中,我每次都创建一个新对象,而在“相同”测试中,我为每次重复截断并重用相同的对象,以排除开销来源。这种开销对于使用具有小数据大小但不是大数据的临时文件很重要。

代码是here

Using 1000 passes with size 1.0KiB
New StringIO:   0.0026 0.0025 0.0034
Same StringIO:  0.0026 0.0023 0.0030
New cStringIO:  0.0009 0.0010 0.0008
Same cStringIO: 0.0009 0.0009 0.0009
New tempfile:   0.0679 0.0554 0.0542
Same tempfile:  0.0069 0.0064 0.0070
==============================================================
Using 1000 passes with size 100.0KiB
New StringIO:   0.0093 0.0099 0.0108
Same StringIO:  0.0109 0.0090 0.0086
New cStringIO:  0.0130 0.0139 0.0120
Same cStringIO: 0.0118 0.0115 0.0124
New tempfile:   0.1006 0.0905 0.0899
Same tempfile:  0.0573 0.0526 0.0523
==============================================================
Using 1000 passes with size 1.0MiB
New StringIO:   0.0727 0.0700 0.0717
Same StringIO:  0.0740 0.0735 0.0712
New cStringIO:  0.1484 0.1399 0.1470
Same cStringIO: 0.1493 0.1393 0.1465
New tempfile:   0.6576 0.6750 0.6821
Same tempfile:  0.5951 0.5870 0.5678
==============================================================
Using 1000 passes with size 10.0MiB
New StringIO:   1.0965 1.1129 1.1079
Same StringIO:  1.1206 1.2979 1.1932
New cStringIO:  2.2532 2.2162 2.2482
Same cStringIO: 2.2624 2.2225 2.2377
New tempfile:   6.8350 6.7924 6.8481
Same tempfile:  6.8424 7.8114 7.8404
==============================================================

两个StringIO 实现相当可比,尽管cStringIO 对于大数据量显着减慢。但是tempfile.TemporaryFile 的时间总是最慢的StringIO 的 3 倍。

【问题讨论】:

  • 我不相信你在这里比较正确的东西。这些答案是关于你的基本 Python 文件包装器——file——而不是tempfile.TemporaryFile
  • @Two-BitAlchemist 我不希望TemporaryFilefile 在读写方面有很大不同。看看tempfileTemporaryFile 实际上是一个返回files 的函数,至少在 POSIX 上(这是我使用的)。 “相同的临时文件”情况应处理创建差异造成的任何开销。

标签: python performance temporary-files stringio cstringio


【解决方案1】:

这完全取决于“经常”是什么意思。 StringIO 是通过将您的写入保存在一个列表中,然后在读取时将该列表连接到一个字符串来实现的。您的测试用例 - 一系列写入,然后是读取 - 是它的最佳方案。如果我调整测试用例以在文件中执行 50 次随机写入/读取,那么 cStringIO 往往会以文件系统位居第二。

该评论似乎反映了系统程序员的偏见,即让 c 库和操作系统来处理文件系统的事情,因为从一般意义上来说,很难猜测在所有条件下什么性能最好。

def write_and_read_test_data(flo):
    fsize = len(closure['test_data'])
    flo.write(closure['test_data'])
    for _ in range(50):
        flo.seek(random.randint(0, fsize-1))
        flo.write('x')
        flo.read(1)
    flo.seek(0)
    closure['output'] = flo.read()

10meg 的测试用例花费的时间比我的注意力还要长...

Using 1000 passes with size 1.0KiB
New StringIO:   0.9551 0.9467 0.9366
Same StringIO:  0.9252 0.9228 0.9207
New cStringIO:  0.3274 0.3280 0.3251
Same cStringIO: 0.3182 0.3231 0.3280
New tempfile:   1.1833 1.1853 1.1650
Same tempfile:  0.9563 0.9414 0.9504
==============================================================
Using 1000 passes with size 100.0KiB
New StringIO:   5.6253 5.6589 5.6025
Same StringIO:  5.5799 5.5608 5.5589
New cStringIO:  0.4157 0.4133 0.4140
Same cStringIO: 0.4078 0.4076 0.4088
New tempfile:   2.0420 2.0391 2.0408
Same tempfile:  1.5722 1.5749 1.5693
==============================================================
Using 1000 passes with size 1.0MiB
New StringIO:   105.2350 106.3904 107.5411
Same StringIO:  108.3744 109.4510 105.6012
New cStringIO:  2.4698 2.4781 2.4165
Same cStringIO: 2.4699 2.4600 2.4451
New tempfile:   6.6086 6.5783 6.5916
Same tempfile:  6.1420 6.1614 6.1366

【讨论】:

  • 天啊!随机访问必须导致StringIO 复制大量数据,因为它由不可变字符串支持。有趣的是:另一个答案声称这是由于 Python 的解释性质,但似乎这实际上并不是罪魁祸首。我刚刚在测试中添加了_pyio.BytesIO:它是用Python 实现的,就像StringIO,但使用可变字节数组。尽管被解释,它只花了两倍于cStringIO 并且仍然击败TemporaryFile。我想我会在另一个问题上添加一个答案。谢谢!
猜你喜欢
  • 2014-10-24
  • 2015-08-03
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 2015-01-16
相关资源
最近更新 更多