使用cython进行并行化

时间:2017-05-04 04:36:15

标签: python python-2.7 parallel-processing cython

下面的代码是否可以并行化?我看着cyton的prange,但无法弄清楚它是如何工作的。 prange是否并行化了不同内核上的内部循环?对于下面的代码,我如何并行化它?

@cython.boundscheck(False)
def gs_iterate_once(double[:,:] doc_topic,
                    double[:,:] topic_word,
                    double[:] topic_distribution,
                    double[:] topic_probabilities,
                    unsigned int[:,:] doc_word_topic,
                    int num_topics):
  cdef unsigned int doc_id
  cdef unsigned int word_id
  cdef unsigned int topic_id
  cdef unsigned int new_topic
  for i in xrange(doc_word_topic.shape[0]):
    doc_id = doc_word_topic[i, 0]
    word_id = doc_word_topic[i, 1]
    topic_id = doc_word_topic[i, 2]

    doc_topic[doc_id, topic_id] -= 1
    topic_word[topic_id, word_id] -= 1
    topic_distribution[topic_id] -= 1

    for j in xrange(num_topics):
      topic_probabilities[j] = (doc_topic[doc_id, j] * topic_word[j, word_id]) / topic_distribution[j]

    new_topic = draw_topic(np.asarray(topic_probabilities))

    doc_topic[doc_id, new_topic] += 1
    topic_word[new_topic, word_id] += 1
    topic_distribution[new_topic] += 1
    # Set the new topic
    doc_word_topic[i, 2] = new_topic

2 个答案:

答案 0 :(得分:3)

prange使用的确是OpenMP shared-memory parallelism。因此,在一台计算机上,它将创建在不同可用核心上运行的线程,并可访问相同的内存池。

对于您显示的例程,第一步是了解哪些部分可以并行化。通常情况下,使用数据作为第一个索引i,仅对元素i进行操作而不是i-1i+1,这会使问题可并行化。这不是这种情况,因此您需要找到一种方法使计算更加独立。

实际上找到特定的并行模式超出了SO的答案,但我会提到一些提示:

  1. 什么是里面 prange必须全部cython化。线程中不可能进行Python调用。 + @DavidW的建议:当with gil块的一部分时,可以进行Python调用。
  2. 这里的一个典型建议是,一旦你的代码独立于循环排序,检查你的结果是否在运行索引时从n-1到0而不是从0到n-1
  3. 一些评论和说明性示例:https://homes.cs.washington.edu/~jmschr/lectures/Parallel_Processing_in_Python.html Cython prange slower for 4 threads then with range http://nealhughes.net/parallelcomp2/ http://www.perrygeo.com/parallelizing-numpy-array-loops-with-cython-and-mpi.html

答案 1 :(得分:3)

@ PierredeBuyl的回答很好地概述了prange做什么以及如何使用它。

这是与您的代码相关的一些具体评论:

  • 您无法并行化外循环:

    doc_topic[doc_id, topic_id] -= 1
    

    以及其他变量和+=1的类似变量。这些修改了在所有循环之间共享的变量,并且会导致不一致的结果。

  • 如果您要对外部循环进行并行化,则topic_probabilities[j] = ...会出现类似的问题。

  • 您可以轻松地对内循环for j in xrange(num_topics):进行并行化 - 这只会修改依赖于索引的内容' j'因此,对于修改相同数据的线程没有任何问题。 (但是,每次启动多线程区域时都会产生性能成本,因此您通常会尝试并行化外部循环,以避免这种情况 - 取决于阵列的大小,您可能无法获得多少)

    < / LI>