2

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.

「実際のファイルの方が速いことが多い」という行は、私には本当に奇妙に思えました。ディスクへの書き込みがメモリへの書き込みよりも優れているのはなぜでしょうか? これらのさまざまなケースのプロファイリングを試みたところ、これらのドキュメントと矛盾する結果と、この質問への回答が得られました。この他の質問は、ここでは連結を行っていませんが、状況によっては cStringIO が遅くなる理由を説明しています。このテストでは、指定された量のデータをファイルに書き込み、最初にシークして読み戻します。「新しい」テストでは毎回新しいオブジェクトを作成し、「同じ」テストでは繰り返しごとに同じオブジェクトを切り捨てて再利用し、オーバーヘッドの原因を排除しました。このオーバーヘッドは、データ サイズが小さいが大きいものではない一時ファイルを使用する場合に重要でした。

コードはこちらです。

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
==============================================================

2 つのStringIO実装はかなり似ていましたが、cStringIOデータ サイズが大きいと速度が大幅に低下しました。しかし、tempfile.TemporaryFile常に最も遅い の 3 倍の時間がかかりましたStringIO

4

1 に答える 1

4

それはすべて、「頻繁に」が何を意味するかに依存します。StringIO書き込みをリストに保持し、読み取り時にリストを文字列に結合することによって実装されます。あなたのテスト ケース (一連の書き込みとそれに続く読み取り) は、その最良のシナリオです。ファイルで 50 回のランダムな書き込み/読み取りを行うようにテスト ケースを微調整するcStringIOと、ファイル システムが 2 位になる傾向があります。

このコメントは、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()

10メガのテストケースは、私の注意力よりも長くかかりました...

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
于 2016-02-03T19:27:03.297 に答える