【问题标题】:Python 多处理拒绝拆分我的可迭代对象
【发布时间】:2022-01-23 04:37:41
【问题描述】:

我正在尝试编写一个多处理程序,似乎我已经完成了,并且我已经使用 System Monitor 应用程序验证了 Python 进程已创建。但问题是,几乎所有这些似乎都没有在现实中使用。在我的程序中,我试图将音频文件分割成块,所以我不认为它是我在其他线程中读到的“微不足道的计算负载”。

对我来说显示相同行为的最小示例:

import os, random, time
from tqdm import tqdm
from multiprocessing import Pool

def myfunc(myli):
    print(len(myli))
    for item in myli:
        x = item*item*item
        time.sleep(2)
    return

mylist = [random.randint(1,10000) for _ in range (0, 19999)]

with Pool(processes=8) as p, tqdm(total=len(mylist)) as pbar:
    for _ in p.imap_unordered(func=myfunc, iterable=(mylist,)):
        pbar.update()

如您所见,我在使用的func 内添加了一个print(),并且每次打印整个数组的长度。好像没有发生分裂一样。

我天真地尝试过使用不同的块大小并删除 tqdm(好像它起了任何作用)。

如果您能给我任何见解,我将不胜感激。

【问题讨论】:

  • 我建议你看看多处理管理器类。您不能在这样的子流程之间共享 mylist。它适用于多线程,因为在这种情况下地址空间是共享的,而且列表是线程安全的
  • @JCaesar 您好,请回答。我记得查看了 Manager 类并没有使用它,因为它似乎有点矫枉过正。为什么你认为这是必要的?据我了解,只需将可迭代对象拆分为不相互通信或不共享数据的进程即可。或者应该是……
  • 也许您可以提供更多关于您需要实现的目标的详细信息,我相信您会得到更完整的答案。另外值得注意的是,您的子流程很可能没有得到充分利用,因为它们大部分时间都在睡觉
  • 我的理解是mylist 不会在进程之间共享,因为它被分成更小的块,每个进程都是独立的。关于细节,它没有什么花哨的。我想处理列表中的一堆项目(字符串)。并且一件物品的处理不影响其他物品的处理。睡眠部分仅用于此处的示例,正​​如我在帖子中所说,我在主应用程序中处理音频文件。

标签: python python-3.x multiprocessing


【解决方案1】:

代码正在做你告诉它做的事情:你传递了一个长度为 1 的迭代,一个包含单个项目的元组 (mylist)。所以它将单个项目传递给单个工作人员进行处理。

但您不能改为使用iterable=mylist,因为myfunc() 期望得到一个序列,而不是整数。无论可迭代对象是什么,multiprocessing 一次将一个元素传递给工作人员。 chunksize 与此无关。无论chunksize 是1 还是10 亿,worker 函数一次只能看到一个元素。 chunksize 是一种隐蔽的优化,纯粹是为了减少所需的昂贵的进程间通信调用的数量。

如果您想将序列拆分为块并使用期望块的工作函数,那么您必须自己进行“分块”。例如,添加

# Generate slices of `xs` of length (at most) `n`.
def chunkit(xs, n):
    start = 0
    while start < len(xs):
        yield xs[start : start + n]
        start += n

并传递iterable=chunkit(mylist, 40)。然后所有 8 个进程都会很忙。一个将在mylist[0:40] 上工作,另一个在mylist[40:80] 上工作,另一个在mylist[80:120] 上工作,以此类推,直到mylist 用尽。

【讨论】:

  • 好的,这个解释正是我需要的。所以当我试图简单地传递mylist 时,我的错误是myfunc 中的for 循环。我不认为流程会逐个处理元素,虽然现在看起来很明显......谢谢蒂姆!
  • 对!将myfunc() 更改为整数,然后原始代码应该可以工作(也使用iterable=mylist)。事情在幕后分块,您可以使用chunksize= 来控制它,但这只是一种优化:它不会改变您的工作函数一次只能看到一个整数。相反,它控制在每个进程间通信调用中发送多少参数。这种分块对您的代码是不可见的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多