4

私は最近 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 を使用しています。もちろん、両方とも同じOSとマシン上にあります(Windows 7)。

どんな助けでも大歓迎です。PyPy は、私がやっていることに対してははるかに高速ですが、ファイルの書き込み速度が 1 秒あたり 0.5 メガバイトに制限されているため、明らかに役に立ちません。

4

4 に答える 4

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]
于 2012-09-25T13:58:06.017 に答える
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 のファイル書き込みが目的に十分な速さである条件を見つけることができると思います。

于 2012-09-25T14:05:47.413 に答える
0

xrangeリストではなくジェネレーターを生成するため、この例の答えです。64 ビットの python は、おそらく 32 ビットの pypy よりも 5000 万個のアイテムを含むリストを生成するのが高速です。

別のコードがある場合は、テストだけでなく、実際のコードを投稿してください。

于 2012-09-25T13:40:19.627 に答える
-1

ここでは2 つのリストを生成していますrange。1 つはリスト内包表記で、もう 1 つはリスト内包表記です。

リスト 1: 1 つのオプションは、返されるリストrangeを generatorに置き換えることxrangeです。もう 1 つは、range-listsと呼ばれる PyPy 独自の最適化を試すことです。

オプションでこの機能を有効にでき–objspace-std-withrangelistます。

リスト 2: 出力リストを作成してから書き込みます。これはジェネレーターでもある必要があるため、リスト内包表記をジェネレーター式に変換します。

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

ジェネレーター式が関数に渡される唯一の引数である限り、括弧を二重にする必要さえありません。

于 2012-09-25T14:05:59.663 に答える