2017-04-11 5 views
0

Ich versuche multi-threaded Gebäude des binären Baumes mit multiprocessing Pool in Python zu implementieren. Die Hauptidee ist, dass, wenn N Hardware-Threads verfügbar sind, ich auf der bestimmten Ebene jeden der Zweige der Struktur in einem separaten Thread erstellen möchte. Es gibt keine Datenabhängigkeiten, und jeder der rekursiven Aufrufe arbeitet mit seinen eigenen Daten, sodass keine Bedenken bezüglich Datenrennen bestehen. Ich bin mit GIL Einschränkungen vertraut, deshalb habe ich mich entschlossen Multiprozessing Pool zu nutzen:Python-Baumbildung mit Multiprocessing-Pool - keine Beschleunigung

pool = Pool(processes=4) 
tree = Tree.createTreeMT(points, pool, 2); 

Das Problem ist, ich bin nicht in der Lage, alle speedups zu bekommen. Die Funktion zum Erstellen der Struktur sieht so aus:

def createTreeMT(points, pool, level = 2): 
    # If there are no more points to process 
    if len(points) < 1: 
     return 

    # Divide points into two groups: 
    left_points = .... 
    right_points = .... 

    tree = Tree() 

    if(level == 0): 
     if len(left_points) > 0: 
      leftPointsResult = pool.apply_async(createTree, (left_points)) 
     if len(right_points) > 0: 
      rightPointsResult = pool.apply_async(createTree, (right_points)) 

     if(leftPointsResult): 
      tree.left = leftPointsResult.get() 
     if(rightPointsResult): 
      tree.right = rightPointsResult.get() 
    else: 
     if len(left_points) > 0: 
      tree.left = createTreeMT(left_points, pool, level-1) 

     if len(right_points) > 0: 
      tree.right = createTreeMT(right_points, pool, level-1) 

    return tree 


def createTree(points): 
    # If there are no more points to process 
    if len(points) < 1: 
     return 

    # Divide points into two groups: 
    left_points = .... 
    right_points = .... 

    tree = Tree() 

    if len(left_points) > 0: 
     tree.left = createTree(left_points) 

    if len(right_points) > 0: 
     tree.right = createTree(right_points) 

    return tree 

Mache ich etwas falsch? Gibt es eine bessere Möglichkeit, solche Aufgabe in Standard Python 2.7 durchzuführen?

Antwort

0

apply_async gibt ein AsyncResult-Objekt zurück, und wenn der Hauptprozess die Funktion "get" aufruft, wird er blockiert, bis das Ergebnis berechnet wird. Ihr Hauptprozess blockiert also immer für jede Unteraufgabe, die er erstellt. Daher keine Beschleunigung!

Eine Option ist die Verwendung der Option "Callback" in apply_async. So Sie folgenden Code ersetzen:

if(level == 0): 
    if len(left_points) > 0: 
     leftPointsResult = pool.apply_async(createTree, (left_points)) 
    if len(right_points) > 0: 
     rightPointsResult = pool.apply_async(createTree, (right_points)) 

    if(leftPointsResult): 
     tree.left = leftPointsResult.get() 
    if(rightPointsResult): 
     tree.right = rightPointsResult.get() 

mit

if(level == 0): 
    if len(left_points) > 0: 
     leftPointsResult = pool.apply_async(
      createTree, (left_points), 
      callback=lambda x: tree.left=x) 
    if len(right_points) > 0: 
     rightPointsResult = pool.apply_async(
      createTree, (right_points), 
      callback=lambda x: tree.right=x) 

wird die Callback-Lambda-Funktion aufgerufen, sobald das Ergebnis bereit ist. Wie Sie im Code sehen können, wird Ihr Baum parallel korrekt gefüllt, da die Ergebnisse von den Pool-Prozessen berechnet werden.

+0

Vielen Dank für Ihre Antwort! Ich musste einige Workarounds tun, um 'Baum' an Callback Lambda zu binden, aber es läuft aktuell. Es gibt mir allerdings keine Beschleunigung - der Code läuft noch langsamer. – pSoLT

+0

Mit wie vielen Punkten testen Sie? Wie viele Kerne haben Sie auf der Maschine, auf der Sie das ausführen? –

+0

Der Code läuft oder i7-6700 CPU mit 4 Kernen und ich teste mit ~ 50000 Punkte, Es mag wie ein wenig scheinen, aber einen Punkt als Vektor von ganzen Zahlen der Größe zwischen 1000 und 10000 betrachten. – pSoLT

Verwandte Themen