Python:AttributeError:无法pickle本地对象'writeBuf。<locals> .write'

时间:2017-08-14 11:48:09

标签: python python-pool

我对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需要它才能正常工作。

什么应该只是一个小小的剧本变成了一个巨大的考验,任何人都能指出正确的方法吗?

1 个答案:

答案 0 :(得分:7)

理论上,python不能腌制功能。 (有关详细信息,请参阅Can't pickle Function

实际上,python会修改函数的名称和模块,以便传递函数。但是,在您的情况下,您尝试传递的函数是writeBuf返回的局部变量。

相反:

  1. 删除writeBuf包装。
  2. 请勿使用write函数的闭包(bufdirectory),而应将write所需的一切作为参数。
  3. 结果:

    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)