将元组列表映射到python中的多处理池对象

时间:2018-06-14 18:33:51

标签: python dictionary multiprocessing tuples pool

我遇到以下格式的代码问题,并假设错误与我试图访问每个元组中的元素的方式有关。

from numberer import numberify
from sys import argv
infile=argv[1]
from multiprocessing import Pool
pool=Pool(15)
import os

def chunker(fob):
    chunkbegin=0
    filesize=os.stat(fob.name).st_size
    while chunkbegin < filesize:
        chunkend=chunkbegin+100000
        fob.seek(chunkend)
        fob.readline()
        chunkend=fob.tell()
        yield (chunkbegin,chunkend)
        chunkbegin=chunkend

def run(tup, fob):
    fob.seek(tup[0])
    length=int(tup[1])-int(tup[0])
    lines=fob.readlines(length)
    for line in lines:
        print(line)

fob=open(infile)
chunks=[x for x in chunker(fob)]
pool.map(run, (chunks, fob))

确切的错误是:

Process ForkPoolWorker-1:
Traceback (most recent call last):
  File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.6/multiprocessing/pool.py", line 108, in worker
    task = get()
  File "/usr/lib/python3.6/multiprocessing/queues.py", line 337, in get
    return _ForkingPickler.loads(res)
AttributeError: Can't get attribute 'run' on <module '__main__' from 'pretonumber.py'>

1)所以当map函数将元组映射到函数时;我假设这些元素应该被称为普通元组? IE有一个索引吗?

2)我传递给函数run的元素块:是一个元组列表: chunks = [(0,100000),(100000,200000)....]由生成器chunker创建。

谢谢。

1 个答案:

答案 0 :(得分:1)

map方法采用可迭代的参数。 iterable的每个元素都传递给run的一个实例。由于您的iterable是元组(chunks, fob),因此这将运行两个任务,在一个任务中调用run(chunks),在另一个任务中调用run(fob)

我认为您要做的是为chunk中的每个chunks运行一项任务,呼叫run(chunk, fob)

首先,您需要一个每个块一次产生(chunk, fob)的迭代,例如((chunk, fob) for chunk in chunks)

但是这仍然不起作用,因为它将使用单个参数调用run,即2元组(chunk, fob),而不是两个参数。您可以通过重写或包装run来获取单个2元组而不是两个单独的参数来解决此问题,或者您可以使用starmap代替map,这样可以为您完成

但这仍然无法奏效。您尝试在进程之间传递打开的文件对象,multiprocessing无法执行此操作。

由于你正在使用fork方法,你有时可以从父级继承文件对象而不是传递它,但细节很复杂,你真的需要阅读{{3对于multiprocessing并了解文件描述符继承如何在Unix上运行。

由于您希望每个孩子都拥有自己的文件对象的独立副本,因此他们可以在其中全部seek,最简单的解决方案是只传递文件名并让它们自己open

def run(tup, path):
    with open(path) as fob:
        fob.seek(tup[0])
        length=int(tup[1])-int(tup[0])
        lines=fob.readlines(length)
        for line in lines:
            print(line)

fob = open(infile)
chunks = [x for x in chunker(fob)]
args = ((chunk, infile) for chunk in chunks)
pool.starmap(run, args)

与此同时,既然我们确信我们不依赖于fork行为,那么编写代码以使用任何start方法可能是个好主意。这意味着将顶级代码放入__main__块。而且,在我们处理它的时候,让我们确保一旦完成它就关闭文件:

# imports
# function definitions
if __name__ == '__main__':
    infile = argv[1]
    pool = Pool(15)
    with open(infile) as fob:
        chunks = [x for x in chunker(fob)]
    args = ((chunk, infile) for chunk in chunks)
    pool.starmap(run, args)

您的代码中可能仍有其他错误,但我认为这会耗尽multiprocessing个错误。