无法将 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
。
我有一个文件,我想使用 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
。