我有一个任务,我的目标是在joblib
-库的帮助下将其并行化。该函数按顺序运行时相当慢,因此我尝试使用并行化范例来加快进程。
with Parallel(n_jobs = -1,verbose = 100) as parallel:
test = parallel(delayed(create_time_series_capacity_v4)(block_info.UnitID[i]) for i in block_info.UnitID.unique())
out_data = pd.concat([out_data,test[test.columns[1]]],axis=1 )
块唯一具有大约1000个条目,并且时间序列的创建对于某些单元来说比其他单元需要更长的时间。这让我想到,一些工人被留下来工作,而另一些工人则在执行一项密集的任务。有没有一种方法可以重用可用的流程,而不是让它们闲置?我在下面粘贴了代码执行时返回的内容:
UNIT05-001 has been written
UNIT04-001 has been written
UNIT05-003 has been written
[Parallel(n_jobs=-1)]: Done 1 tasks | elapsed: 0.2s
[Parallel(n_jobs=-1)]: Done 2 out of 10 | elapsed: 0.2s remaining: 1.2s
[Parallel(n_jobs=-1)]: Done 3 out of 10 | elapsed: 0.2s remaining: 0.7s
UNIT05-004 has been written
[Parallel(n_jobs=-1)]: Done 4 out of 10 | elapsed: 0.4s remaining: 0.7s
UNIT05-002 has been written
[Parallel(n_jobs=-1)]: Done 5 out of 10 | elapsed: 0.6s remaining: 0.6s
UNIT02-001 has been written
[Parallel(n_jobs=-1)]: Done 6 out of 10 | elapsed: 27.9s remaining: 18.5s
UNIT01-001 has been written
[Parallel(n_jobs=-1)]: Done 7 out of 10 | elapsed: 50.4s remaining: 21.5s
我对joblib
不太熟悉,但我很快就仔细阅读了文档。看起来您正在使用默认的";多处理";基于Pythonsmultiprocessing.Pool
实现的后端,对此我确实有所了解。这个类创建了一个进程池,正如您所期望的那样。您的1000个任务被放置在";任务队列";(请参见下面的阻塞(。池中的每个进程最初都是空闲的,因此它们各自从队列中删除一个任务并执行各自的任务。当进程完成执行任务时,它将再次变为空闲状态,因此它将返回以检索队列中的下一个任务。这种情况一直持续到队列中不再有任务,此时所有处理器都保持空闲,直到添加了另一个任务。
我们不能假设通常是每个任务运行所需的时间相等。但为了便于论证,我们假设所有任务执行所需的时间相等。如果您提交1000个任务由16个处理器处理,那么在每个进程执行了62个任务(16*62=992(之后,任务队列上将只剩下8个任务要执行。在这种情况下,8个进程将保持空闲,而其他8个进程执行最后8个任务。但是,除非这些任务运行时间很长,否则您会看到所有16个进程都处于空闲状态,并且或多或少同时保持这种状态。现在让我们假设,除了最后一个提交的任务外,所有任务都需要相同的时间,该任务的执行时间要长15分钟。现在,您可能会看到15个进程或多或少同时处于空闲状态,而第16个处理器在空闲之前需要额外的15分钟。但是,如果这个额外的长时间运行的任务是提交的第一个任务,那么您会再次看到所有处理器同时处于空闲状态。当然,在假设其他任务完成所需的时间要少得多的情况下,执行长时间运行的任务的进程最终处理的任务将少于其他进程。
阻塞
multiprocessing.Pool
支持分块;CCD_ 5是否使用该能力。但这就是它的工作方式:
由于读取和写入任务队列可能相当昂贵,为了减少对任务队列的操作数量,池可以将提交的任务批处理为特定大小的块。也就是说,池可以将任务写入16个任务的块中,而不是一次一个地将1000个任务写入队列,作为可能的块大小的示例。因此,当处理器变为空闲时,它从任务队列中获得包含16个任务的下一个块。在执行完所有16个任务之前,进程不会变为空闲,只有这样,进程才会尝试获得下一个任务块。
因此,如果使用大小为16的块,那么将有62个大小为16(16*62=992个任务(的块被放置在队列上,加上总共63个块的8个任务的最终块。在16个进程中的每一个都执行了3个块(16*3=48个块(之后,队列上将剩下15个块。因此,其中一个进程将立即闲置。在剩下的15个处理器中,请记住,其中一个块只包含8个任务,而不是16个任务。这个进程将在其他14个进程之前变为空闲,每个进程在其最终块中还有8个任务要执行。
结论
上面的例子基于所有任务都需要相同的时间来运行,这不是很现实,但仍然应该让你了解事情是如何工作的。