web-dev-qa-db-ja.com

Python:AttributeError:ローカルオブジェクト 'writeBuf。<locals> .write'をピクルできません

私はPythonにまったく精通していませんが、通常RubyまたはJSです。ただし、Pythonを実行するシステムでベンチマークスクリプトを記述する必要があります。私がやろうとしていることは、ファイルサイズとスレッド数を取得し、ランダムバッファーを書き込む小さなスクリプトこれは、2時間いじった後に得られたものです。

from multiprocessing import Pool
import os, sys

def writeBuf(buf):
    def write(n):
        f = open(os.path.join(directory, 'n' + str(n)), 'w')
        try:
            f.write(buf)
            f.flush()
            os.fsync(f.fileno)
        finally:
            f.close()
    return write

if __name__ == '__main__':
    targetDir = sys.argv[1]
    numThreads = int(sys.argv[2])
    numKiloBytes = int(sys.argv[3])
    numFiles = int(102400 / numKiloBytes)

    buf = os.urandom(numKiloBytes * 1024)

    directory = os.path.join(targetDir, str(numKiloBytes) + 'k')
    if not os.path.exists(directory):
        os.makedirs(directory)

    with Pool(processes=numThreads) as pool:
        pool.map(writeBuf(buf), range(numFiles))

しかし、それはエラーをスローします:AttributeError: Can't pickle local object 'writeBuf.<locals>.write'

以前にクロージャーなしでwriteを使用しようとしましたが、__name__ == '__main__'パーツ内で関数を定義しようとするとエラーが発生しました。 ifを省略するとエラーにもなり、Poolが機能するためにはエラーが必要であると読みました。

小さなスクリプトが巨大な試練に変わったはずですが、誰かが私を正しい方向に向けることができますか?

7
Lanbo

理論的には、python cann't pickle functions。(詳細については、 Ca n't pickle Function) を参照してください)

実際には、pythonは、関数の名前とモジュールをピクルス化して、関数を渡すことが機能するようにします。ただし、あなたの場合、渡そうとしている関数は、writeBuf

代わりに:

  1. writeBufラッパーを削除します。
  2. write関数のクロージャー(bufおよびdirectory)を使用せず、代わりにwriteに必要なすべてをパラメーターとして指定してください。

結果:

def write(args):
    directory, buf, n = args

    with open(os.path.join(directory, 'n' + str(n)), 'w') as f:
        # might as well use with-statements ;)
        f.write(buf)
        f.flush()
        os.fsync(f.fileno)

if __name__ == '__main__':
    ...

    with Pool(processes=numThreads) as pool:
        nargs = [(directory, buf, n) for n in range(numFiles)]
        pool.map(write, nargs)
11
Hetzroni