1

我正在尝试在 Mac OSX 上的 python (2.7.8) 中使用多处理。在阅读了 Velimir Mlaker 对这个问题的回答后,我能够使用 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
4

1 回答 1

1

最新的 git 提交music21具有帮助处理多处理的一些棘手部分的功能,基于 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 线程)上,并行运行比串行运行慢近 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()

于 2016-02-01T14:54:45.540 回答