python 中无法 pickle 的多进程任务?
Multiprocess tasks in python that can't be pickled?
我正在尝试在 Mac OSX 上使用 python (2.7.8) 中的多处理。在阅读 Velimir Mlaker 对此 question 的回答后,我能够使用 multiprocessing.Pool() 对一个非常简单的函数进行多处理,但它不适用于我的实际函数。我得到了正确的结果,但它是串行执行的。我认为问题在于我的函数循环遍历 music21.stream() ,它类似于列表但具有音乐数据的特殊功能。我相信 music21 流不能被腌制,所以我可以使用一些多处理替代池吗?我不介意返回的结果是否乱序,如有必要,我可以升级到不同版本的 python。我已经包含了我的多处理任务代码,但没有包含它调用的 stream_indexer() 函数的代码。谢谢!
import multiprocessing as mp
def basik(test_piece, part_numbers):
jobs = []
for i in part_numbers:
# Each 2-tuple in jobs has an index <i> and a music21 stream that
# corresponds to an individual part in a musical score.
jobs.append((i, test_piece.parts[i]))
pool = mp.Pool(processes=4)
results = pool.map(stream_indexer, jobs)
pool.close()
pool.join()
return results
music21
的最新 git 提交具有基于 joblib 的功能,可帮助解决多处理中一些比较棘手的部分。例如,如果你想计算一个部分中的所有音符,你通常可以连续做:
import music21
def countNotes(s):
return len(s.recurse().notes)
# using recurse() instead of .flat to avoid certain caches...
bach = music21.corpus.parse('bach/bwv66.6')
[countNotes(p) for p in bach.parts]
并行它是这样工作的:
music21.common.runParallel(list(bach.parts), countNotes)
但是!这是一个巨大的警告。让我们计时:
In [5]: %timeit music21.common.runParallel(list(b.parts), countNotes)
10 loops, best of 3: 152 ms per loop
In [6]: %timeit [countNotes(p) for p in b.parts]
100 loops, best of 3: 2.19 ms per loop
在我的计算机上(2 核,4 线程),运行ning 并行比串行 运行ning 慢近 100 倍。为什么?因为准备要进行多处理的 Stream 的开销很大。如果 运行 的例程非常慢(大约 1 毫秒/音符除以处理器数量),那么值得在多处理中传递 Streams。否则,看看是否有办法只来回传递少量信息,例如处理路径:
def parseCountNotes(fn):
s = corpus.parse(fn)
return len(s.recurse().notes)
bach40 = [b.sourcePath for b in music21.corpus.search('bwv')[0:40]]
In [32]: %timeit [parseCountNotes(b) for b in bach40]
1 loops, best of 3: 2.39 s per loop
In [33]: %timeit music21.common.runParallel(bach40, parseCountNotes)
1 loops, best of 3: 1.83 s per loop
在这里,即使在 MacBook Air 上,我们也开始获得加速。在我的办公室 Mac Pro 上,对于这样的调用,加速会变得很大。在这种情况下,对 parse
的调用在对 recurse()
.
的时间内占主导地位
我正在尝试在 Mac OSX 上使用 python (2.7.8) 中的多处理。在阅读 Velimir Mlaker 对此 question 的回答后,我能够使用 multiprocessing.Pool() 对一个非常简单的函数进行多处理,但它不适用于我的实际函数。我得到了正确的结果,但它是串行执行的。我认为问题在于我的函数循环遍历 music21.stream() ,它类似于列表但具有音乐数据的特殊功能。我相信 music21 流不能被腌制,所以我可以使用一些多处理替代池吗?我不介意返回的结果是否乱序,如有必要,我可以升级到不同版本的 python。我已经包含了我的多处理任务代码,但没有包含它调用的 stream_indexer() 函数的代码。谢谢!
import multiprocessing as mp
def basik(test_piece, part_numbers):
jobs = []
for i in part_numbers:
# Each 2-tuple in jobs has an index <i> and a music21 stream that
# corresponds to an individual part in a musical score.
jobs.append((i, test_piece.parts[i]))
pool = mp.Pool(processes=4)
results = pool.map(stream_indexer, jobs)
pool.close()
pool.join()
return results
music21
的最新 git 提交具有基于 joblib 的功能,可帮助解决多处理中一些比较棘手的部分。例如,如果你想计算一个部分中的所有音符,你通常可以连续做:
import music21
def countNotes(s):
return len(s.recurse().notes)
# using recurse() instead of .flat to avoid certain caches...
bach = music21.corpus.parse('bach/bwv66.6')
[countNotes(p) for p in bach.parts]
并行它是这样工作的:
music21.common.runParallel(list(bach.parts), countNotes)
但是!这是一个巨大的警告。让我们计时:
In [5]: %timeit music21.common.runParallel(list(b.parts), countNotes)
10 loops, best of 3: 152 ms per loop
In [6]: %timeit [countNotes(p) for p in b.parts]
100 loops, best of 3: 2.19 ms per loop
在我的计算机上(2 核,4 线程),运行ning 并行比串行 运行ning 慢近 100 倍。为什么?因为准备要进行多处理的 Stream 的开销很大。如果 运行 的例程非常慢(大约 1 毫秒/音符除以处理器数量),那么值得在多处理中传递 Streams。否则,看看是否有办法只来回传递少量信息,例如处理路径:
def parseCountNotes(fn):
s = corpus.parse(fn)
return len(s.recurse().notes)
bach40 = [b.sourcePath for b in music21.corpus.search('bwv')[0:40]]
In [32]: %timeit [parseCountNotes(b) for b in bach40]
1 loops, best of 3: 2.39 s per loop
In [33]: %timeit music21.common.runParallel(bach40, parseCountNotes)
1 loops, best of 3: 1.83 s per loop
在这里,即使在 MacBook Air 上,我们也开始获得加速。在我的办公室 Mac Pro 上,对于这样的调用,加速会变得很大。在这种情况下,对 parse
的调用在对 recurse()
.