4

Python での単純なアプローチを使用したファイルのコピーは、通常、次のようになります。

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

(ちなみに、このコード スニペットは shutil.py からのものです)。

残念ながら、これには私の特別なユースケース (スレッド化と非常に大きなバッファを含む) では欠点があります [イタリック体の部分は後で追加]。まず、read() の呼び出しごとに新しいメモリ チャンクが割り当てられ、次の反復で buf が上書きされると、このメモリが解放され、同じ目的のために新しいメモリが再度割り当てられることを意味します。これにより、プロセス全体が遅くなり、ホストに不要な負荷がかかる可能性があります。

これを回避するために、私は file.readinto() メソッドを使用していますが、残念ながら、非推奨であり、「使用しない」と文書化されています。

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    buffer = array.array('c')
    buffer.fromstring('-' * length)
    while True:
        count = fsrc.readinto(buffer)
        if count == 0:
            break
        if count != len(buffer):
            fdst.write(buffer.toString()[:count])
        else:
            buf.tofile(fdst)

私の解決策は機能しますが、欠点も 2 つあります。まず、readinto() を使用しないでください。なくなるかもしれません(ドキュメントによると)。第二に、 readinto() を使用すると、バッファに読み込むバイト数を決定できず、 buffer.tofile() を使用して書き込みたいバイト数を決定できないため、最後のブロックの面倒な特殊なケース (これも不必要に高い)。

私はarray.array.fromfile()を見てきましたが、「そこにあるすべて」を読み取るために使用することはできません(読み取り、次にEOFErrorをスローし、処理されたアイテムの数を配布しません)。また、エンディングの特殊ケースの問題に対する解決策ではありません。

私がやりたいことをする適切な方法はありますか?たぶん、私が望むことをする単純なバッファクラスまたは類似のものを見落としているだけです。

4

2 に答える 2

5

このコード スニペットは shutil.py からのものです

これは標準ライブラリモジュールです。なぜそれを使用しないのですか?

まず、read() の呼び出しごとに新しいメモリ チャンクが割り当てられ、次の反復で buf が上書きされると、このメモリが解放され、同じ目的のために新しいメモリが再度割り当てられることを意味します。これにより、プロセス全体が遅くなり、ホストに不要な負荷がかかる可能性があります。

これは、実際にディスクから 1 ページのデータを取得するために必要な労力に比べれば、ごくわずかです。

于 2012-03-20T17:25:12.613 に答える
3

通常の Python コードは、このような微調整を行う必要はありません - ただし、Python コード内からファイルを読み取るためにパフォーマンスの微調整が本当に必要な場合 (たとえば、作成したサーバー coe を書き換えていて、パフォーマンスのために既に動作している場合や、メモリ使用量) ctypes を使用して OS を直接呼び出したいので、必要なだけ低レベルでコピーを実行します。

「cp」実行可能ファイルを外部プロセスとして単純に呼び出すことは、あなたのケースではハードルが少なくなる可能性さえあります(そして、すべてのOSおよびファイルシステムレベルの最適化を最大限に活用できます)。

于 2012-03-20T17:35:04.753 に答える