2013-10-17 102 views
2

我正試圖學習如何在Python中使用多處理。 我讀到multiprocessing,我試圖做這樣的事情:並行處理 - 池 - Python

我有以下類(部分碼),它具有產生Voronoi圖的方法:

class ImageData:  

    def generate_voronoi_diagram(self, seeds): 
    """ 
    Generate a voronoi diagram with *seeds* seeds 
    :param seeds: the number of seed in the voronoi diagram 
    """ 
    nx = [] 
    ny = [] 
    gs = [] 
    for i in range(seeds): 
     # Generate a cell position 
     pos_x = random.randrange(self.width) 
     pos_y = random.randrange(self.height) 
     nx.append(pos_x) 
     ny.append(pos_y) 

     # Save the f(x,y) data 
     x = Utils.translate(pos_x, 0, self.width, self.range_min, self.range_max) 
     y = Utils.translate(pos_y, 0, self.height, self.range_min, self.range_max) 
     z = Utils.function(x, y) 

     gs.append(z) 

    for y in range(self.height): 
     for x in range(self.width): 
      # Return the Euclidean norm 
      d_min = math.hypot(self.width - 1, self.height - 1) 
      j = -1 
      for i in range(seeds): 
       # The distance from a cell to x, y point being considered 
       d = math.hypot(nx[i] - x, ny[i] - y) 
       if d < d_min: 
        d_min = d 
        j = i 
      self.data[x][y] = gs[j] 

我必須生成一個大量的這些圖表,所以這消耗了很多時間,所以我認爲這是一個典型的並行化問題。 我這樣做,在「正常」的方式,像這樣:

if __name__ == "__main__": 
    entries = [] 
    for n in range(images): 
     entry = ImD.ImageData(width, height) 
     entry.generate_voronoi_diagram(seeds) 
     entry.generate_heat_map_image("ImagesOutput/Entries/Entry"+str(n)) 
     entries.append(entry) 

試圖並行這一點,我想這樣的:

if __name__ == "__main__": 
    entries = [] 
    seeds = np.random.poisson(100) 
    p = Pool() 
    entry = ImD.ImageData(width, height) 
    res = p.apply_async(entry.generate_voronoi_diagram,(seeds)) 
    entries.append(entry) 
    entry.generate_heat_map_image("ImagesOutput/Entries/EntryX") 

但是,除了它不工作,甚至不生成一個單一的圖,我不知道如何指定這必須做N次。

任何幫助將不勝感激。 謝謝。

回答

1

Python的多處理不共享內存(除非你明確告訴它)。這意味着您不會看到在工作進程中運行的任何函數的「副作用」。您的generate_voronoi_diagram方法的作用是將數據添加到entry值,這是一個副作用。爲了查看結果,您需要將它作爲函數的返回值傳回。

這裏有一個辦法,處理entry實例作爲參數和返回值:在

if __name__ == "__main__": 
    entries = [ImD.ImageData(width, height) for _ in range(images)] 
    seeds = numpy.random.poisson(100, images) # array of values 

    pool = multiprocessing.Pool() 
    for i, e in enumerate(pool.starmap_async(do_voroni, zip(entries, seeds))): 
     e.generate_heat_map_image("ImagesOutput/Entries/Entry{:02d}".format(i)) 

e值:

def do_voroni(entry, seeds): 
    entry.generate_voronoi_diagram(seeds) 
    return entry 

現在,你可以在你的工作進程使用這個功能循環不參考entries列表中的值。相反,它們是這些對象的副本,它們被傳遞給工作進程(向其添加數據)並返回。

+0

Huuum,謝謝。但是我得到一個「AttributeError:'Pool'對象沒有屬性'starmap_async'」。但看着參考書我可以找到這種方法。 – pceccon

+0

是的,實際上,我沒有安裝Python 3,因爲我需要使用的其他東西,比如matplotlib,有些東西根本無法使用。有可能以另一種方式做?此外,種子對於所有voronoi圖都是唯一的 - 它代表網站的數量。 – pceccon

+0

@pceccon:啊,它看起來'starmap'方法只在Python 3中。您可以在Python 2中使用'map_async'方法,但是您需要將'do_voroni'函數更改爲接受一個2元組,該函數可以在函數體中解壓縮以獲得'entry'和'seeds'值:'' def do_voroni(tup):entry,seeds = tup; ...' – Blckknght

0

我可能是錯的,但我認爲你應該使用

解析度= p.apply_async(entry.generate_voronoi_diagram,(種子))

res.get(超時= 1)

你可能會無法泡菜式「instancemethod」

我認爲最簡單的方法是一樣的東西

import random 
from multiprocessing import Pool 


class ImageData: 

    def generate_voronoi_diagram(self, seeds): 
     ooxx 

    def generate_heat_map_image(self, path): 
     ooxx 

def allinone(obj, seeds, path): 
    obj.generate_voronoi_diagram(seeds) 
    obj.generate_heat_map_image(path) 

if __name__ == "__main__": 
    entries = [] 
    seeds = random.random() 
    p = Pool() 
    entry = ImageData() 
    res = p.apply_async(allinone, (entry, seeds, 'tmp.txt')) 
    res.get(timeout=1)