Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 04, 2025 04:10

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 09:01 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Hallo,
Ich bin grade dabei, für die PasGUI einen Polygon-Triangulator zu schreiben, der möglichst effizient sein soll.

Vereinfacht gesagt, schneidet die Hauptprozedur das Polygon in zwei Teile, die beide per Rekursion weiter zerschnitten werden. Diese Methode erhält einen nur für sie bestimmten Input, auf den niemand anderer zugreift. Das bedeuted, dass jede Rekursion immer ihre eigenen Daten hat. Das habe ich so gemacht, damit man es später parallelisieren kann. Andererseits kostet das Kopieren der Daten natürlich auch Zeit, je größer das Polygon, umso mehr Daten sind zu kopieren.

(Das soll bei Polygonen mit mehr als vier Vertices verwendet werden. Einfache Quads kriegen eine einfachere Verarbeitungsmethode.)

Frage: vertragen sich Threads mit Rekursionen? Bzw. ist das überhaupt ein sinnvoller Ansatz im Hinblick auf das Kopieren der Daten?

Vielen Dank im Voraus,
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 09:15 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Wie viele Vertices haben deine Polygone den? Reden wir hier von weniger als 20-30 oder eher 1000 und mehr?

Im ersten Fall sehe ich nicht was eine Parallelisierung bringen soll. Sofern du nicht unbedingt eine perfekte Triangulierung (z.B. Delaunay) brauchst empfehle ich dir den ziemlich einfachen Corner-Cutting-Algorithmus. Insbesondere wenn deine Polygone garantiert konvex sind ist der sehr schnell.
Für die konkave 3D-Variante kann ich dir sogar C++-Code geben. Ich habe mir dafür eine Ring-Datenstruktur gebaut, quasi einen std::vector der beim Indexzugriff vorher ein Modulo macht. Das vereinfacht die Implementierung enorm. :)
Der Corner-Cutting-Algorithmus hat für konkave Polygone einen quadratischen Aufwand. Für kleine Polygone ist das aber wahrscheinlich das einfachste/schnellste was du machen kannst.

Bei 1000 und mehr Vertices kann eine Parallelisierung möglicherweise Sinn machen. Da du aber wahrscheinlich mehr als ein Polygon triangulieren willst ist sinnvoller und einfache pro Polygon einen Thread zu benutzen. Dann musst du auch keine Daten kopieren.

Zitat:
Frage: vertragen sich Threads mit Rekursionen?

Ja, jeder Thread hat einen eigenen Stack. Solange du also den Datenzugriff sicherst (z.B. durch kopieren) ist das kein Problem.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 09:20 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Rekursive Funktionen sind nicht wirklich gut Parallelisierbar, da ja nach beendigung ein neuer job, stack/auf/abbau statt findet .
Es macht mehr sinn, deine Geometry in n Teile zu teilen, wobei n die Anzahl der Cores ist. Dann kann jeder thread das gebiet vollständig tesselieren.
Nachteil, du hast durch das zerschneiden extra Triangle dem könnte man aber nur entgehen, wenn nach dem durcharbeiten von allen Bereichen noch ein Schritt macht, der die restlichen Lücken auffüllt, die durch die Überlappung von Punkten in ein anderen Teil nicht trianguliert werden(sonnst hätte man ein Triangle mehrfach).
Also zusammen gefasst folgendes.
-anzahl der kerne ermitteln
-boundingbox vom mesh ermitteln
-box in n Bereiche Unterteilen
-jeden thread ein Bereich zuteilen und die Punktliste(die im Bereich liegen) übergeben
-Thread:-normales tesselieren
-warte bis alle threads fertig sind
-übrig gebliebende Löscher stopfen

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 10:25 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Tak2004 hat geschrieben:
Rekursive Funktionen sind nicht wirklich gut Parallelisierbar, da ja nach beendigung ein neuer job, stack/auf/abbau statt findet .
Es macht mehr sinn, deine Geometry in n Teile zu teilen, wobei n die Anzahl der Cores ist. Dann kann jeder thread das gebiet vollständig tesselieren.
Ok, klingt plausibel.

Tak2004 hat geschrieben:
Nachteil, du hast durch das zerschneiden extra Triangle dem könnte man aber nur entgehen, wenn nach dem durcharbeiten von allen Bereichen noch ein Schritt macht, der die restlichen Lücken auffüllt, die durch die Überlappung von Punkten in ein anderen Teil nicht trianguliert werden(sonnst hätte man ein Triangle mehrfach).
Nein, ich kriege zwar eine Vertexliste überreicht, aber ich arbeite intern nur mit den Integer-Indices, und wenn man ein Polygon in mehrere Teile zerschneidet, müssen nacher mehr Indizes rauskommen. Das ist kein Problem. Ein erstes Debugging hat ergeben, dass er das einigermaßen hinkriegt.

Coolcat hat geschrieben:
Wie viele Vertices haben deine Polygone den? Reden wir hier von weniger als 20-30 oder eher 1000 und mehr?
Die Triangluation soll dem Benutzer der PasGUI ermöglichen, selber Formen zu definieren, die per Kontour eingelesen und anschließend trianguliert werden. Deshalb kann ich Dir jetzt nicht sagen, wie viel Vertices das sind. Aber ganz wenige sind es vermutlich nicht: die einfachen Formen stellt das Programm zur Verfügung. Also so etwas zum Beispiel: die Form eines Cockpits.

Coolcat hat geschrieben:
Sofern du nicht unbedingt eine perfekte Triangulierung (z.B. Delaunay) brauchst
Ich habe einen optionalen Post-Processing Delauney-Schritt geplant, aber noch nicht implementiert.

Coolcat hat geschrieben:
brauchst empfehle ich dir den ziemlich einfachen Corner-Cutting-Algorithmus. Insbesondere wenn deine Polygone garantiert konvex sind ist der sehr schnell.

Wir reden hier von einem Triangulator, der in die PasGUI eingebaut wird. Die PasGUI ist für mich so etwas wie ein Referenz-Implementierung. Das wird Open Source. Und ich möchte da etwas wirklich Gutes einbauen. Derzeit halte ich bei einem Algorithmus, der das Ear-Cutting verbessert, indem er das Bottleneck in dem Algo durch eine Sweep-Line Methode drastisch verkürzt.

Aber im wesentlichen schneidet er Ecken ab, genau wie ein ganz normaler Ear-Cutter. Perfekt, naja, ziemlich sicher nicht. Aber ein Schlußlicht soll er auch nicht sein.

Zitat:
Für die konkave 3D-Variante kann ich dir sogar C++-Code geben. Ich habe mir dafür eine Ring-Datenstruktur gebaut, quasi einen std::vector der beim Indexzugriff vorher ein Modulo macht. Das vereinfacht die Implementierung enorm. :)
Der Corner-Cutting-Algorithmus hat für konkave Polygone einen quadratischen Aufwand. Für kleine Polygone ist das aber wahrscheinlich das einfachste/schnellste was du machen kannst.

Ich will nichts Einfaches. Und ja, ich würde mir Deinen Algo gerne ansehen. Im Gegenzug biete ich Dir meinen, allerdings ist er noch nicht fertig. Für die Ring-Datenstruktur - die ich natürlich auch brauche - habe ich mir eine Predecessor/Successor Funktion gebaut und verwende ein ordinäres dynamisches Array..

Den Quadratischen Aufwand hab ich ein wenig in den Griff bekommen, siehe oben. Aber auch nur theoretisch. Derzeit habe ich auch nicht viel mehr in der Hand als einen Ear-Cutter.

Weils mir grade einfällt: ich ziele auf das Triangulieren von Letter-Outlines ab, das bedeutet: er muss auch Löcher können. Und ich will meinen alten Modeller ausmotten und wieder lauffähig machen. Der Triangulierer, den ich dort vor Urzeiten mal eingebaut habe, hatte einen Bug. Das möchte ich jetzt natürlich auch hinkriegen.

Und danke Euch beiden für den Hinweis bezüglich Rekursion&Threads. Ich denk mal, damit kann ich wirklich etwas anfangen. :wink:
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 10:44 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Ich will nichts Einfaches. Und ja, ich würde mir Deinen Algo gerne ansehen.

Bitte :)

Sieht ein wenig länglich aus, der eigentliche Kern des Algos (die Doppelschleife) hat aber nur 28 Zeilen.

Code:
/***************************************************************************
 *   Copyright (C) 2010 by Martin Weusten                                  *
 *   martin dot weusten (ät" rwth minus aachen.de                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

void BuildingPolyhedron::triangulate(CGAL::Polyhedron polyhedron,
                                     std::vector<CML::Vector3f>& triangleList)
{
   CGAL::Polyhedron::Facet_iterator itrFace = polyhedron.facets_begin();
   CGAL::Polyhedron::Facet_iterator endFace = polyhedron.facets_end();
   for (; itrFace != endFace; ++itrFace) {
      CGAL::Polyhedron::Facet face = (*itrFace);

      // extract polygon vertices
      Ring<CML::Vector3f> polygon(face.facet_degree());
      CGAL::Polyhedron::Facet::Halfedge_around_facet_const_circulator circHalfEdge, endHalfEdge;
      circHalfEdge = endHalfEdge = face.facet_begin();
      for (; circHalfEdge != endHalfEdge; ++circHalfEdge) {
         polygon.add(toVector3f(circHalfEdge->vertex()->point()));
      }
   
      // triangulate polygon
      triangulate(polygon, triangleList);
   }
}

void BuildingPolyhedron::triangulate(CDL::Ring<CML::Vector3f> polygon,
                                     std::vector<CML::Vector3f>& triangleList)
{
   int size = polygon.size();
   Q_ASSERT_X(size >= 3, "BuildingPolyhedron", "A polygon with less than 3 vertices?");

   // compute face normal and projection
   CML::Vector3f normal = CML::faceNormal(polygon[0], polygon[1], polygon[2]);
   CML::Vector3f axis0(1,0,0);
   if (abs(axis0 * normal) > 0.8) { axis0 = CML::Vector3f(0,1,0); }
   CML::Vector3f axis1 = axis0 % normal;
   axis0 = axis1 % normal;
   CML::Matrix33f projection(axis0, axis1, normal);

   // project vertices into 2D space and find minimum x value
   float minValue = CML::FLOAT_MAX;
   int minIndex = -1;
   Ring<CML::Vector2f> polygon2D(size);
   for (int i=0; i<size; ++i) {
      CML::Vector3f vertex = polygon[i] * projection;
      polygon2D.add(CML::Vector2f(vertex.x, vertex.y));
      if (vertex.x < minValue) {
         minValue = vertex.x;
         minIndex = i;
      }
   }

   // get sign of convex vertices (minimum vertex must be convex)
   int convexSign = CML::sgn(adjacentEdgeCross(polygon2D, minIndex));

   // generate triangles using curner cutting algorithm
   for (int i=0; size>3; ++i) {
      // skip concave corners
      if (adjacentEdgeCross(polygon2D, i) * convexSign < 0) { continue; }

      // extract the triangle
      const CML::Vector2f& A = polygon2D[i-1];
      const CML::Vector2f& B = polygon2D[i  ];
      const CML::Vector2f& C = polygon2D[i+1];

      // check if other vertex is inside the triangle
      bool vertexInside = false;
      for (int j=i+2; j<i+size-1 && !vertexInside; ++j) {
         // skip convex corners
         if (adjacentEdgeCross(polygon2D, j) * convexSign > 0) { continue; }
         // check if vertex j is inside triangle ABC
         vertexInside = CML::pointInTriangle2D(A,B,C,polygon2D[j]);
      }
      if (vertexInside) { continue; }

      // ok, let's cut the corner
      triangleList.push_back(polygon[i-1]);
      triangleList.push_back(polygon[i  ]);
      triangleList.push_back(polygon[i+1]);
      polygon.remove(i);
      polygon2D.remove(i);
      --size;
      --i;
   }
   // add remaining triangle
   triangleList.push_back(polygon[0]);
   triangleList.push_back(polygon[1]);
   triangleList.push_back(polygon[2]);
}

inline float BuildingPolyhedron::adjacentEdgeCross(const Ring<CML::Vector2f>& vertices2D, const int corner) {
   CML::Vector2f edge1 = vertices2D[corner-1] - vertices2D[corner];
   CML::Vector2f edge2 = vertices2D[corner+1] - vertices2D[corner];
   return edge1 % edge2;
}


namespace CDL {

   /** A dynamic array with circular access methods.
    * Circular means that index access is always modulo the current size.
    * E.g index \c -1 does map to the last element.
    * @author Martin Weusten */
   template<typename T>
   class Ring {
   public:
      /** Create new Ring with given initial capacity. */
      Ring(const int capacity = 5);
      Ring(const Ring<T>& r);
      ~Ring();

      Ring<T>& operator=(const Ring<T>& r);

      /** Add element at the end. Operation takes constant runtime if capacity is sufficient */
      void add(const T& x);

      /** Remove a specific element.
        * Note that this method works circular. Operation takes linear runtime. */
      void remove(int i);

      /** Set size to zero. */
      inline void clear() { m_size = 0; }

      inline bool empty() const { return m_size == 0; }
      inline int size() const { return m_size; }
      inline int capacity() const { return m_capacity; }
      
      /** Resize the internal array. Elements at the end are dropped if the
       * capacity is smaller than the current size. Operation takes linear runtime. */
      void capacity(const int n);

      /** Access element at index. Note that this operator works circular. */
      inline T& operator[](const int i) {
         return m_data[mod(i, m_size)];
      }

      /** Access element at index. Note that this operator works circular. */
      inline const T& operator[](const int i) const {
         return m_data[mod(i, m_size)];
      }
   private:
      T* m_data;
      int m_size;
      int m_capacity;
      float m_growFactor;

      /** Simple modulo which does also work for negative a. */
      static inline int mod(const int a, const int n) {
         int r = a - n * (a/n);
         return r < 0 ? r+n : r;
      }
   };

   // ...

}


_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 11:48 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Vielen Dank. Da will ich natürlich nicht nachstehen. Ist aber, wie gesagt, erst im werden. Die eigentliche Triangulierung findet in den Methoden "SplitPolygon" und "GetDiagonal" statt. Und damit es nicht zu lang wird, stell ich nur diese beiden hier rein. Kaum getestet, daher höchstwahrscheinlich noch nicht lauffähig.

Das Transformieren 3D=>2D habe ich auch nocht nicht. Ich wollte das eigentlich nur rotieren/verschieben, aber Du hast vermutlich recht und man wird es auf eine Ebene projizieren müssen.

Code:
//********************************************************************
Function TTesselator.SplitPolygon(APolygon: TIndexList): TBool32;
//----------------------------------------------------
Procedure CreateContour(AInternPoly: TIndexList;
                     ANewCount,AOldIndex: TTessIndex);
Var NewIndex,OldIndex: TTessIndex;
Begin
   OldIndex:= AOldIndex;
   For NewIndex:= 0 To ANewCount-1 Do Begin
      AInternPoly[NewIndex]:= APolygon[OldIndex];
      OldIndex:= Successor(OldIndex,Length(APolygon));
   End;
End;
//----------------------------------------------------
Var
   Polygon0,Polygon1: TIndexList;
   Count0,Count1,Index0,Index1,Actual,I: TTessIndex;
   Found: TBool32;
Begin
   Result:= FALSE;
    Found:= GetDiagonal(APolygon,Index0,Index1);

   If Found
   Then Begin

      // Create first polygon ----------------------------------
      If Index1 > Index0
      Then Count0:= Index1-Index0+1
      Else Count0:= Length(APolygon)-(Index0-Index1)+1;
      SetLength(Polygon0,Count0);
      CreateContour(Polygon0,Count0,Index0);

      If Length(Polygon0) > 3
      Then SplitPolygon(Polygon0) // RECURSE with first polygon
      Else Begin  // End: write triangle to output
         Move(Polygon0[0],fTriangles[fActSlot],3*SizeOf(TTessIndex));
         Inc(fActSlot,3);
      End;
      Finalize(Polygon0);

      // Create second polygon ---------------------------------
      Count1:= Length(APolygon)-Count0+2;
      SetLength(Polygon1,Count1);
      CreateContour(Polygon1,Count1,Index1);

      If Length(Polygon1) > 3
      Then SplitPolygon(Polygon1) // RECURSE with second polygon
      Else Begin  // End: write triangle to output
         Move(Polygon1[0],fTriangles[fActSlot],3*SizeOf(TTessIndex));
         Inc(fActSlot,3);
      End;
      Finalize(Polygon1);
     
      Result:= TRUE;
   End
   Else Raise ETesselError.Create('Could not split polygon');
End;
//********************************************************************
Function TTesselator.GetDiagonal(APolygon: TIndexList;
                   Var AIndex0,AIndex1: TTessIndex): TBool32;
Var
   RotationType: TRotationType;
   Prior,Actual,Next,Count,Trouble,I: TTessIndex;
   FoundTrouble: TBool32;
   ActP,PriorP,NextP,SomeP: TTessVertex2D;
Begin
   // Find first ear
   Count:= Length(APolygon);
   RotationType:= rotNone;

   I:= 0;
   While RotationType <> rotCCW Do
   Begin
      Actual:= I;
      Prior:= Predecessor(Actual,Count);
      Next:= Successor(Actual,Count);

      PriorP:= fContour[APolygon[Prior]];
      ActP  := fContour[APolygon[Actual]];
      NextP := fContour[APolygon[Next]];

      RotationType:= GetRotationType
         (fContour[APolygon[Prior]],
          fContour[APolygon[Actual]],
          fContour[APolygon[Next]]);

      Inc(I); //============>
   End;

   // If this is an ear, then we have to look for trouble :)
   If RotationType = rotCCW
   Then Begin
      I:= Successor(Next,Count);
      FoundTrouble:= FALSE;

      While (I <> Prior) And (Not FoundTrouble) Do
      Begin
         SomeP:= fContour[APolygon[I]];
         If (I <> Actual) And (I <> Prior) And (I <> Next) And
            (PointInTriangle(fContour[APolygon[I]],
                fContour[APolygon[Prior]],
                fContour[APolygon[Actual]],
                fContour[APolygon[Next]]))
            Then Begin
               Trouble:= I;
               FoundTrouble:= TRUE;
            End
            Else I:= Successor(I,Count); //=======>
      End;
   End;

   If RotationType = rotCCW  // This is an ear!
   Then Begin
      If Not FoundTrouble
         Then Begin AIndex0:= Prior; AIndex1:= Next; End
         Else Begin AIndex0:= Actual; AIndex1:= Trouble; End;
      Result:= TRUE;
   End
   Else Result:= FALSE;
End;
//********************************************************************






EDIT: Ich seh grade, Du hast einen intelligenten Point in Poygon-Test. Genau diese Stelle ist der Bottleneck, nicht wahr? Weil man im Prinzip alle Punkte prüfen muss.

Ich habe mir meine Implementierung ungefähr so vorgestellt: beim Sweep-Line-Verfahren braucht man eine sortierte Indexliste (die Punkte sind nach X/Y-Koordinaten sortiert). Beim Ear-Cutting ziehe ich dann eine Bounding Box um das Triangle, das ich abschneiden will - sollte programmiertechnisch eigentlich kein großer Aufwand sein, jedenfalls nicht so viel wie das Checken eines Vertex - und werfe dann einen Blick in die sortierte Liste, stelle fest, dass KEIN Vertex (oder vielleicht nur wenige) in der Bounding Box liegt, dann brauch ich die Suche nach möglichen Punkten im Dreieck gar nicht anzufangen. Wenn ich dann auch die Sortierung noch möglichst billig hinkriege, verspreche ich mir davon schon einen merkbaren Geschwindigkeitsvorteil. Sollte einer linearen Zeit schon recht nahe kommen. :wink:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 13:36 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Ich seh grade, Du hast einen intelligenten Point in Poygon-Test. Genau diese Stelle ist der Bottleneck, nicht wahr?

Würde ich jetzt nicht intelligent nennen, aber ja...du musst nur konkave Eckpunkte testen. Denn wenn eine konvexe Ecke im Dreieck liegt, dann auch eine konkave. Ob ein Punkt konkav oder konvex ist testest du über das 2D-Kreuzprodukt der beiden adjazenten Kanten des Eckpunktes, der Test ist also recht flott. Ich habe bei mir sowieso nur in Ausnahmefällen konkave Polygone, da lohnt sich ein solcher Test natürlich.

Übrigens: Du sprichst von Löchern in deinen Polygonen? In der mir bekannten Variante kann Corner-Cutting damit nicht umgehen.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 14:51 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Nein, kann meiner derzeit auch nicht. Ich werde das als preprocessing Step einfügen. Ob Löcher in meinen Polygonen sind, ist mir bekannt, denn der Benutzer muss die Lochkontur extra übergeben. Dann die beiden Konturen aufschneiden und die Lochkontour an der richtigen Stelle in der richtigen Reihenfolge in die Polygonkontour einfügen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 18:51 
Offline
DGL Member

Registriert: Do Mai 30, 2002 18:48
Beiträge: 1617
Zitat:
Rekursive Funktionen sind nicht wirklich gut Parallelisierbar, da ja nach beendigung ein neuer job, stack/auf/abbau statt findet

??? Also insbesondere wenn das Teile und Herrsche Prinzip greift ist man doch oft super fein raus. Einfach in den ersten paar Rekursionsebenen neue Threads auf den verschiendenen Teilen der Daten aufmachen - man muss nur aufpassen, weil man ganz schnell exponentiell viele Threads erzeugt :-) Gibt zwar auch TuH die sich nur schwer parallelisieren lassen, wie etwa die Suche im Binärbaum, aber beim Quicksort z.B. klappts prima, weil der sich immer auf zwei verschiedenen Teilen der Daten aufruft.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Do Apr 15, 2010 18:58 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
wie etwa die Suche im Binärbaum,

Die Suche im Binärbaum ist auch nicht wirklich rekursiv....ich würd es jedenfalls in einer Schleife implementieren ;)

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Fr Apr 16, 2010 08:16 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Wie wäre es mit einem anderen Ansatz der Paralelisierung. Die bisherigen Vorschläge gehen immer davon aus, dass jetzt etwas berechnet werden muss und das auch so schnell wie möglich. In dem Moment kann man nur hergehen und versuchen den Aufwand so gut wie möglich zu verteilen. Es ändert aber nichts an der Sache, dass man auf das Ergebniss warten muss. Wenn man Glück hat muss man nur 1/2 oder 1/4tel der Zeit warten. Vielleicht sollte man versuchen das Warten ganz zu vermeiden.

Bei Spielen etc. läuft es ja auch so ab, dass die Befehle zum Zeichnen der Szene abgesetzt werden und wärend die GPU die Daten verarbeitet werden auf der CPU bereits die Physikberechnungen für die nächste Szene durchgeführt. Das SwapBuffers erzwingt dann, dass alle Daten von der GPU verarbeitet wurden. Wenn man zwischenzeitlich etwas anderes gemacht hat, dann hat man zwar nicht die Arbeit beschleunigt sondern nur das Warten verkürzt. Das Beispiel bezieht sich auch nur auf einen SingleCore+GPU (= 2 Cores). Da aktuelle System fast immer mehrere CPU Kerne besitzen, läuft so etwas generell in einem anderen Thread ab.

Ich weiß nicht in wie fern das in die Struktur passt. Allerdings wenn 2 CPU Kerne vorhanden sind wäre es doch ideal, wenn die Daten bereits berechnet wurden wenn sie benötigt werden. Man müsste also "nur" dafür sorgen, dass das Berechen frühzeitig angeworfen wird. Bei 3+ Kernen kann man den Algorithmus immer noch zerlegen. Wobei sich dann auch immer der Synchronisieroverhead erhöht. Bei den Datenmengen die ein Mensch per Hand erzeugt (GUI) behaupte ich einfach mal, dass der Vorteil dann wohl auch schon fast von dem Overhead aufgefressen wird. Dadurch hätte man zwar eine Paralelisierung aber Nichts wirklich gewonnen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Rekursion&Threads
BeitragVerfasst: Fr Apr 16, 2010 11:43 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Lossy hat geschrieben:
Ich weiß nicht in wie fern das in die Struktur passt.

Meine ToDo-Liste für die PasGUI ist noch nicht zu Ende. Eine Triangulierung steht jetzt an. Mein Problem dabei ist, dass ich so eine Triangulierung auch an einer anderen Stelle brauche. Die beiden Dinge sind aber ziemlich unterschiedlich.

Szenario 1: die GUI.
Da hab ich vorgesehen, dass sich jemand eine Kontur bastelt (wie und wo, weiß ich jetzt noch nicht so genau), und das ganze dann als Vorlage für ein Panel benutzt. Öhm, damit die GUI aufhört, wie ein Office-Produkt auszusehen :roll: . Die Daten werden in Form einer Vertexliste (sollte ein winziges File sein) geladen und *einmal* trianguliert und dann in den GRam geladen - aus. Hier gibt es bestimmt keine Geschwindigkeitsprobleme.

Szenario 2: der Modeller.
Hier hab ich das Problem, dass neuere OpenGL-Versionen nur Triangles nehmen. Wenn etwas modelliert wird, sollte es auch gleich angezeigt werden. Aber bei dem Gedanken, Modelle mit Triangle-Meshes zu erzeugen, bricht mir der kalte Angstschweiß aus. Dreiecke sind gut für den Renderer, aber jemand, der vor dem Bildschirm sitzt und modellieren will, wird von Dreiecken behindert (mir gehts zumindest so).

Das heißt, hauptsächlich werden Quads erzeugt. Polygone mit mehr Vertices kommen vor, aber selten. Hier muss der Triangulierer schnell sein. Da muss er das soeben erzeugte Polygon entgegennehmen und *sofort* bearbeiten und dann schnell irgendwie zu allen anderen dazuschmeißen und ab gehts zum Rendern. Das stell ich mir stressig vor.




Im Prinzip heißt das für mich, dass ich einen Triangulierer brauch, der eben alles kann. Und ehrlich: schadet uns das was, wenn ich der PasGUI einen schnellen Pascal-Triangulierer spendiere? :wink:


Aus den oben gegeben Antworten lese ich Folgendes raus (nur so als Feedback):

Grundsätzlich kann man Threads zusammen mit Rekursionen benutzen. Den Vorteil der Schnelligkeit hat man aber nur, wenn die Rekursionen (ihrer Natur nach) zumindest teilweise unabhängig voneinander sind. Das trifft für meine obige Methode "SplitPolygon" nur mit Einschränkung zu, weil ich das Polygon in zwei Teile breche und anschließend für jeden der beiden Teile wieder "SplitPolygon" aufrufe.

Wie die Triangulierung im Einzelnen ablaufen wird - und ob man daher einen Vorteil aus dem Multithreading ziehen kann - kann man nicht voraussagen, weil der Triangulierungs-Fortschritt vom stark einzelnen Polygon abhängig ist.

Als Beispiel: angenommen, mein Polygon hat die Form eines "V". Wenn die Funktion "SplitPolygon" Glück (!) hat, erwischt sie das "V" dort, wo die beiden Extremitäten des V zusammentreffen, denn dann wird er das V in zwei gleich große Stücke schneiden und jeden extra für sich verarbeiten. Anschließend degeneriert er aber leider zu einem Eckenabschneider (er "mampft" die beiden Schenkel des V stückchenweise 8) ), und genau dort geht der Geschwindigeitsvorteil des Multithreading imho verloren.

Noch schlimmer wäre es, wenn einer der beiden Schenkel des V viel länger wäre als der andere, denn da müsste der kürzere so lange warten, bis der längere fertig ist, denn ich denk mal, es wird nur weitergemacht, wenn beide Rekursionen wieder zurückkehren. Also ich interpretiere das so, das so etwas wie eine Synchronisierung auf jedem Rekursions-Level zwangsweise stattfindet.

Die *Form* des Polygons nimmt also einen (nicht linearen) Einfluß auf die Laufzeit des Algo und zwar viel stärker als bei der oben erwähnten binären Suche. Da die Form nicht vorhersehbar ist, ist eine Optimierung schwer möglich. Ich kann mich ja täuschen, schließlich verstehe ich nichts vom Compilerbau, aber ich finde, so unrecht hat Tak gar nicht. Ich hätte mit dem Multithreading der Rekursion nur eine relativ kleine Chance auf bessere Performance.

Lossy hat geschrieben:
Bei den Datenmengen die ein Mensch per Hand erzeugt (GUI) behaupte ich einfach mal, dass der Vorteil dann wohl auch schon fast von dem Overhead aufgefressen wird. Dadurch hätte man zwar eine Paralelisierung aber Nichts wirklich gewonnen.
Ja. Und wie man oben sieht, ist der Vorteil so klein, dass er nicht mal beim automatischen Erzeugen eine Rolle spielt. Ich lass es also lieber bleiben. Nichtsdestotrotz (was für ein Wort :wink:) ist es hin und wieder gut, auch ein paar andere Meinungen zu hören.

Viele Grüße und Danke nochmal
Traude


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 15 Queries | GZIP : On ]