无法将 class 对象传递给 Python 中的星图?

Cannot pass class object to starmap in Python?

我有一个文件,我想使用 Python 的多处理 class 以并行方式处理它。我当前的代码是:

class rand:
    def __init__(self):
        self.rando = "world"

def do_work2(obj, line):
    return line + obj.rando

if __name__ == "__main__":

    num_workers = cpu_count() - 2
    pool = Pool(num_workers)
    ran = rand()
    with open("sample.txt") as f:
        # chunk the work into batches of 4 lines at a time
        results = pool.starmap(do_work2, zip(ran,f), 4)

    print(results)

我希望看到我文件中的所有行最后都有一个串联的“世界”。但是,当我 运行 这段代码时,我得到:

TypeError: 'rand' object is not iterable

我知道为什么会这样,但我只是想知道是否有一种方法可以将 class 对象发送到一个函数,然后在该函数中使用 class 对象,所有这同时进行多处理。

有人可以帮我吗?

是的,您可以将 class 对象传递给多处理函数,但 zip 需要将可迭代参数传递给它。这样的事情可能更直观一点:

args = [(ran, f) for i in range(10)]
results = pool.starmap(do_work2, args)

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool.starmap

请记住,创建对象的副本并将其发送到每个进程

试试这个:


ran = rand()
with open("sample.txt") as f:
    # repeat the ran
    ran_lines = [ran for _ in range(len(f))]
    # chunk the work into batches of 4 lines at a time
    results = pool.starmap(do_work2, zip(rand_lines, f), 4)

正如 Michael 所指出的,错误的出现是因为 zip 期望它的每个参数都是可迭代的,而你的 rand class 不是。虽然 Chems 的修复有效,但它会不必要地占用内存,并且不会考虑文件的大小。我更喜欢这样:

from itertools import repeat

pool.starmap(do_work2, zip(repeat(ran), f), 4)

repeat 产生无限数量的 ran 对象(直到你停止要求它们)。这意味着它将产生与 f 有多少行一样多的 ran,而无需在提供给 zip 之前在单独的列表中占用内存,也无需计算有多少行 f有。

我只是放弃使用 pool.starmap 而使用普通的 pool.map。您可以将您的函数包装在另一个函数中,并提供 ran 作为第一个参数。有两种方法可以做到这一点。 quick-and-dirtylambda方式:

pool.map(lambda line: do_work2(ran, line), f, 4)

或者,可以说更正确的使用方法 partial:

from functools import partial

pool.map(partial(do_work2, obj=ran), f, 4)

请参阅 here 了解为什么您可能更喜欢 partial 而不是普通的 lambda