6

次のコードスニペットがあります

def send(self, queue, fd):
    for line in fd:
        data = line.strip()
        if data:
            queue.write(json.loads(data))

もちろんどちらでも問題なく動作しますが、空白以外の行にのみ作用する構造を作成するための「より良い」方法があるのではないかと思うことがあります。

課題は、これが「fd」読み取りの反復的な性質を使用し、100MB以上の範囲のファイルを処理できるようにする必要があることです。

更新-この質問のポイントを急いで取得するために、メモリ使用量であるインポート部分を無視しています。たとえば、次の式です。

 non_blank_lines = (line.strip() for line in fd if line.strip())

strip()アクションを2回実行することは言うまでもなく、ファイル全体をメモリにバッファリングします。これは小さなファイルでは機能しますが、100 MB以上のデータがある場合(または100 GB以上の場合)は失敗します。

挑戦の一部は次の作品ですが、読むべきスープです:

for line in ifilter(lambda l: l, imap(lambda l: l.strip(), fd)):
    queue.write(json.loads(line))

魔法の人を探してください!

最終更新:PEP-289は、イテレータを使用した場合の[]と()の違いを理解するのに非常に役立ちます。

4

2 に答える 2

4

書かれているコードには何の問題もありません。読みやすく効率的です。

別のアプローチは、ジェネレーターの理解としてそ​​れを書くことです:

def send(self, queue, fd):
    non_blank_lines = (line.strip() for line in fd if line.strip())
    for line in non_blank_lines:
        queue.write(json.loads(data))

このアプローチは、イテレータを使用できる関数を適用する場合に役立ちます(terser)。例:python3 print

non_blank_lines = (line.strip() for line in fd if line.strip())
print(*non_blank_lines, file='foo')

strip()への複数の呼び出しをなくすには、ジェネレーター内包表記を連鎖させます

stripped_lines = (line.strip() for line in fd)
non_blank_lines = (line for line in stripped_lines if line)

このpepで詳しく説明されているように、ジェネレータ式はメモリに悪影響を与えないことに注意してください。

このアプローチといくつかのパフォーマンスベンチマークの詳細については、この一連のメモを参照してください。

最後に、strip()の完全な動作が必要ない場合、rstrip()はstrip()よりもパフォーマンスが優れていることに注意してください。

于 2012-12-03T17:35:18.350 に答える
1

自分よりも「良い」方法はありません。想定どおりに機能し、読みやすいなどです。ただし、速度を「良い」と分類すると、微調整を確実に行うことができます。

私はPythonでのこの速度に関するものにあまり慣れていませんが、特定の条件下でのみ機能するいくつかの提案があります。他の誰かがもっと良いものを思いつくことを願っています、多分この答えは彼らを助けるでしょう。

ファイルに次のような行が含まれない場合

       \n

ただし、代わり\nに、この方法の方が著しく高速になります。

def send(self, queue, fd):
    for line in fd:
        if line != '\n':
            queue.write(json.loads(line.strip()))

Timeit値:

using: strip() :: 1.8722578811916337
using: line != '\n' :: 1.0126976271093881
using: line != '\n' and line != ' \n' :: 1.2862439244170275

ただし、これは実際にはさらに遅くなる可能性があることに注意してください。ファイルに1行がない場合は、\nfdを使用してタイミングを調整しました。["string", "\n", "test string", "\n", "moreeee", "\n", "An other element"]

線が遅いかどうかはおそらくわかりませんが\n.strip()かなり遅いので、もっと良い方法があるかもしれません。

于 2012-12-03T18:19:46.560 に答える