2017-05-04 177 views
0

下面的代码可以并行化吗?我看着Cyton的prange,但无法弄清楚它是如何工作的。 prange是否将不同内核上的内部环路并行化?对于下面的代码,我该如何并行化它?使用cython并行化

@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

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

对于您演示的例程,第一步是了解哪些部分可以并行化。通常,使用作为第一索引i的数据,仅在元件i上操作而不是例如i-1i+1,使得问题可并行化。这不是这种情况,所以你需要找到一种方法使计算更加独立。

真正找到特定的并行模式超出了SO回答,但我会提一些建议:

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

回复点1 - 我可以建议一个补充:如果你把它们放在一个'gil:'块中,允许Python调用。只要这是循环的一小部分,那么性能成本并不算太差。 – DavidW

2

@ PierredeBuyl的回答给出了什么prange做和如何使用它的一个很好的轮廓。

这是更涉及代码的一些具体意见:

  • 您不能并行外环:

    doc_topic[doc_id, topic_id] -= 1 
    

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

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

  • 你可以很容易地并行内部循环for j in xrange(num_topics): - 这只会修改依赖于索引'j'的东西,所以不存在争取修改相同数据的线程问题。 (但是,每次启动一个多线程的区域时的性能为代价的,所以通常尝试并行外环来避免这一点 - 这取决于数组的大小,你可能没有太大的收获)