Strategien für die parallele Abarbeitung von Listen (c++ unter Linux)



  • loks schrieb:

    Das bringt natürlich nur dann etwas wenn mehrere Cores zur Verfügung stehen _und_ der Algorithmus auch parallelisierbar ist, ansonsten ist es nutzlos. Threads an sich bringen keine Performance sondern kosten Selbige (-> Context Switching).

    Ja es stehen 8 Cores zur Verfügung.
    Und die Methode "Gemeindeüberprüfung" hat keine weiteren Abhängigkeiten

    loks schrieb:

    ehm, was? Kannst Du das mal erklären, vor allem welchen Sinn das machen soll? Warum sollte der Thread nicht einfach bis zum Ende der Abarbeitung durchlaufen?

    Das ganze ist nur ein Beispiel für mein eigentlich Problem und es ist leichter wenn man das einfach als eine Gegebenheit hinnimmt, zb. weil man den verwendeten Core nicht ständig auf 100% CPU last haben möchte (nur so als Beispiel).

    loks schrieb:

    Indem man zuerst einmal analysiert _warum_ der Algorithmus so lange braucht und dann gezielt das Bottleneck angeht. Einfach nur "mehr Threads" gegen ein Performanceproblem werfen ist verhältnismässig Sinnfrei.

    Eine Gemeindeüberprüfung dauert einfach so lange, da kann man nichts mehr wegoptimieren.

    BITTE
    Ich suche Strategien bzgl. paralleler Abarbeitung die mir hier helfen könnten. DANKE


  • Mod

    taff schrieb:

    loks schrieb:

    ehm, was? Kannst Du das mal erklären, vor allem welchen Sinn das machen soll? Warum sollte der Thread nicht einfach bis zum Ende der Abarbeitung durchlaufen?

    Das ganze ist nur ein Beispiel für mein eigentlich Problem und es ist leichter wenn man das einfach als eine Gegebenheit hinnimmt, zb. weil man den verwendeten Core nicht ständig auf 100% CPU last haben möchte (nur so als Beispiel).

    Dies ist aber ein ungeheuer wichtiger Punkt in der Aufgabenbeschreibung. Und deine Erklärung ist unbefriedigend. Was ist denn das für eine komische Aufgabenstellung? Durchsuche alles aber auch irgendwie doch nicht? Hier besteht ganz entscheidender Klärungsbedarf, bevor wir dir wirklich weiter helfen können. Ich habe sogar die Vermutung, dass sich am Ende rausstellen wird, dass diese Nebenklausel Unsinn ist, aber das kann ich erst mit Gewissheit beurteilen, wenn du es genauer erklärt hast. Jedenfalls klingt es sehr ungewöhnlich.

    Ich suche Strategien bzgl. paralleler Abarbeitung die mir hier helfen könnten.

    Ganz allgemein: Aufgabe in Unteraufgaben aufteilen. Da gibt es sicher auch bessere Möglichkeiten, als gemachte Teile als gemacht zu markieren. Zum Beispiel in dem ein Thread die erste Hälfte nimmt, der andere die zweite. Aber dies würde das Ergebnis bezüglich deiner komischen 100 Prüfungsklausel vollkommen verändern. Dies ist einer der Gründe, warum es wichtig ist, dass du diesen Teil genauer erklärst, sonst kann man dir keine konkreten Ratschläge geben und es bleibt bei "Aufgabe aufteilen".



  • taff schrieb:

    Und die Methode "Gemeindeüberprüfung" hat keine weiteren Abhängigkeiten

    Also keine Filezugriffe, keine Datenbankzugriffe, keine Zugriffe auf eine externe URL zur Prüfung? Einfach nur irgendeine Art von Berechnung die komplett in Memory auf dem Inhalt des Vektors stattfindet?



  • SeppJ schrieb:

    Dies ist aber ein ungeheuer wichtiger Punkt in der Aufgabenbeschreibung. Und deine Erklärung ist unbefriedigend. Was ist denn das für eine komische Aufgabenstellung? Durchsuche alles aber auch irgendwie doch nicht? Hier besteht ganz entscheidender Klärungsbedarf, bevor wir dir wirklich weiter helfen können. Ich habe sogar die Vermutung, dass sich am Ende rausstellen wird, dass diese Nebenklausel Unsinn ist, aber das kann ich erst mit Gewissheit beurteilen, wenn du es genauer erklärt hast. Jedenfalls klingt es sehr ungewöhnlich.

    Wie gesagt ein Grund dafür ist zb. die CPU-Auslastung, weil kaum ist alles abgearbeitet muss alles von vorne beginnen -> dauerhaft 100% CPU Last auf einem Core.
    Dadurch hüpft man wieder raus in die eigentlich Thread-Schleife und hat dort noch so Nebengeräusche zu überprüfen ob der Thread noch weiterlaufen soll oder nicht (falls der Service beendet wird, muss jeder Thread beendet werden)
    Es ist auch nicht wichtig, dass man in einer Sekunde alles 1000x überprüft, sondern man kann somit das ganze "gemütlicher" angehen, aber trotzdem flott, somit sagen wir einfach, dass nach jeder 100sten Überprüfung eine Pause gemacht wird.

    SeppJ schrieb:

    Ganz allgemein: Aufgabe in Unteraufgaben aufteilen. Da gibt es sicher auch bessere Möglichkeiten, als gemachte Teile als gemacht zu markieren. Zum Beispiel in dem ein Thread die erste Hälfte nimmt, der andere die zweite.

    Das aufteilen wäre eine Möglichkeit jedoch verändert sich dann doch eher oft die Anzahl von den Gemeinden und die Zuteilung wäre nicht so einfach bzw. hat jedes Bundesland nicht die selbe Anzahl von Gemeinden.

    loks schrieb:

    Also keine Filezugriffe, keine Datenbankzugriffe, keine Zugriffe auf eine externe URL zur Prüfung? Einfach nur irgendeine Art von Berechnung die komplett in Memory auf dem Inhalt des Vektors stattfindet?

    Nein, da die Daten in den Gemeinde-Objekten von einem anderen Thread aufbereitet werden und nur dann aktualisiert werden, wenn gerade die Gemeinde nicht gelockt ist.


  • Mod

    Wozu ist die Pause gut, was passiert da? Ist die Aufgabe nun alles zu durchsuchen oder doch nicht? Was ist das gewünschte Ergebnis wenn sich mittendrin die Daten ändern? Wieso ist die CPU-Auslastung wichtig? Soll die Aufgabe nun so schnell wie möglich erfolgen oder nicht? Soll im Hintergrund noch irgendeine GUI flüssig reagieren? Ist das das Problem? Wenn du so geheimnisvoll tust, dann können wir nur raten. Es klingt jedenfalls stark so, als läge hier ein XY-Problem vor (Wenn du nicht weißt, was das bedeutet -> Google_.

    und hat dort noch so Nebengeräusche zu überprüfen ob der Thread noch weiterlaufen soll oder nicht (falls der Service beendet wird, muss jeder Thread beendet werden)

    Oder ist dies der Grund? Einen Abbruch der Suchfunktion wenn irgendein Flag gesetzt wird erreichst du doch auch wesentlich einfacher. Eben indem du genau solch ein Flag überprüfst.

    Nein, da die Daten in den Gemeinde-Objekten von einem anderen Thread aufbereitet werden und nur dann aktualisiert werden, wenn gerade die Gemeinde nicht gelockt ist.

    Oder ist dies der Grund? Muss die Liste zwischendurch aktualisiert werden?

    Du meinst das sicherlich gut, dass du für uns das Problem vereinfachst, aber so wie du es machst, wird es für uns stattdessen zum Ratespiel.

    Das aufteilen wäre eine Möglichkeit jedoch verändert sich dann doch eher oft die Anzahl von den Gemeinden und die Zuteilung wäre nicht so einfach bzw. hat jedes Bundesland nicht die selbe Anzahl von Gemeinden.

    Es gibt auch andere Methoden. Kommt eben drauf an. Zum Beispiel eine Task queue, eventuell gekoppelt mit einem Threadpool.



  • sorry, aber basierend auf den Informationen kann ich auch nicht mehr sagen als Sepp schon gesagt hat.

    taff schrieb:

    t auch nicht wichtig, dass man in einer Sekunde alles 1000x überprüft, sondern man kann somit das ganze "gemütlicher" angehen, aber trotzdem flott, somit sagen wir einfach, dass nach jeder 100sten Überprüfung eine Pause gemacht wird.

    Diese Aussage macht für mich absolut keinen Sinn. Wenn Du alles in einer Sekunde 1000x überprüfen kannst, wo ist dann das Performanceproblem???



  • ich krystalkugele mal waghalsig.

    es gibt einen thread A:
    -- der durch eine liste geht, dabei lockt dieser thread die liste.

    es gibt einen thread B:
    -- der gerne auf die liste zugreifen moechte um sie zu modifizieren, was er nicht kann, da thread A immer was zu tun hat und die liste somit 99.999% der zeit gelockt ist.

    jetzt extrapoliere ich weiter zu der schlauen loesung:
    Thread A:
    -- durchsucht die liste mit einem counter der pro element hochgezaehlt wird und bei z.B. counter==1000 -> liste unlock; sleep(100); liste lock und nochmal von vorne ueber die elemente iterieren bis der thread bei einem nicht markierten glied der liste ankommt und da weiter arbeitet.

    @taff ist etwas davon falsch?



  • Klingt ein wenig nach sinnlosem polling, vllt sollte man das Problem komplett anders angehen.
    Erklär doch mal was du für ein Problem lösen willst (am ende) und nicht wie du es lösen möchtest.



  • SeppJ schrieb:

    Wozu ist die Pause gut, was passiert da? Ist die Aufgabe nun alles zu durchsuchen oder doch nicht? Was ist das gewünschte Ergebnis wenn sich mittendrin die Daten ändern? Wieso ist die CPU-Auslastung wichtig? Soll die Aufgabe nun so schnell wie möglich erfolgen oder nicht? Soll im Hintergrund noch irgendeine GUI flüssig reagieren? Ist das das Problem? Wenn du so geheimnisvoll tust, dann können wir nur raten. Es klingt jedenfalls stark so, als läge hier ein XY-Problem vor (Wenn du nicht weißt, was das bedeutet -> Google_.

    und hat dort noch so Nebengeräusche zu überprüfen ob der Thread noch weiterlaufen soll oder nicht (falls der Service beendet wird, muss jeder Thread beendet werden)

    Oder ist dies der Grund? Einen Abbruch der Suchfunktion wenn irgendein Flag gesetzt wird erreichst du doch auch wesentlich einfacher. Eben indem du genau solch ein Flag überprüfst.

    Nein, da die Daten in den Gemeinde-Objekten von einem anderen Thread aufbereitet werden und nur dann aktualisiert werden, wenn gerade die Gemeinde nicht gelockt ist.

    Oder ist dies der Grund? Muss die Liste zwischendurch aktualisiert werden?

    Du meinst das sicherlich gut, dass du für uns das Problem vereinfachst, aber so wie du es machst, wird es für uns stattdessen zum Ratespiel.

    tut mir leid, dass ich das nun doch zu kompliziert wiedergebe.
    Ja ein Grund ist, dass ich immer wieder zurückkehre ist, dass der Abbruch des Threads nur in der Thread-Schleife passieren sollte und nicht in anderen Strukturen, da ich diese ja Grundsätzlich nichts wissen müssen über den Thread der darunter liegt.
    Desweiteren muss der Thread immer wieder Lebenszeichenabsetzen für div. Statisktikaufzeichnungen usw.
    Und da auf der Maschine noch weitere Services laufen, kann ich mir nicht einfach 100% eines Cores schnappen.
    Auch andere Threads können auf diese Datenstruktur zugreifen.

    SeppJ schrieb:

    Es gibt auch andere Methoden. Kommt eben drauf an. Zum Beispiel eine Task queue, eventuell gekoppelt mit einem Threadpool.

    Das hört sich schon interessanter an 🙂 Und klingt ähnlich dem was ich schon geschrieben habe:

    taff schrieb:

    Macht man zusätzlich noch einen Vector der alle Gemeinden aller Bundesländer enthält und kopiert sich diesen Vector (mit den shared_ptr-members) zusätzlich noch in einen temporären Vector und entfernt die Gemeinde die gerade überprüft wurde und wenn der temp-Vector leer ist macht man wieder eine Kopie und beginnt von vorne?

    Die Frage die ich mir hier stelle wieviel Last erzeugt das kopieren des Vectors oder der queue?
    Wie würde die Sache mit dem Threadpool aussehen? Ein Thread der die Queue immer weider füllt und div. Worker-Threads?

    rapso schrieb:

    ich krystalkugele mal waghalsig.

    es gibt einen thread A:
    -- der durch eine liste geht, dabei lockt dieser thread die liste.

    es gibt einen thread B:
    -- der gerne auf die liste zugreifen moechte um sie zu modifizieren, was er nicht kann, da thread A immer was zu tun hat und die liste somit 99.999% der zeit gelockt ist.

    jetzt extrapoliere ich weiter zu der schlauen loesung:
    Thread A:
    -- durchsucht die liste mit einem counter der pro element hochgezaehlt wird und bei z.B. counter==1000 -> liste unlock; sleep(100); liste lock und nochmal von vorne ueber die elemente iterieren bis der thread bei einem nicht markierten glied der liste ankommt und da weiter arbeitet.

    @taff ist etwas davon falsch?

    Ja das ist schon sehr nah an dem wie ich es habe.
    Es gibt eben dann später Thread A1 und A2
    Problem ist der sinnlose Overhead mit dem Durchlauf bis zum nicht markierten Objekt.

    ScottZhang schrieb:

    Klingt ein wenig nach sinnlosem polling, vllt sollte man das Problem komplett anders angehen.
    Erklär doch mal was du für ein Problem lösen willst (am ende) und nicht wie du es lösen möchtest.

    Grundsätzlich hätte ich gerne div. Lösungwege gelesn oder ob es hier so eine Art Design-Patterns auch für ständiges paralleles Abarbeiten von Listen gibt 🙂
    Problem ist eher der Overhead, dass ich zu den Elementen komme die abgearbeitet gehören.


  • Mod

    taff schrieb:

    Und da auf der Maschine noch weitere Services laufen, kann ich mir nicht einfach 100% eines Cores schnappen.

    Läuft das Ding auf Windows 3.11 oder was? So etwas ist Aufgabe eines Schedulers, der über diesen Diensten läuft, nicht der Dienste selber.



  • SeppJ schrieb:

    taff schrieb:

    Und da auf der Maschine noch weitere Services laufen, kann ich mir nicht einfach 100% eines Cores schnappen.

    Läuft das Ding auf Windows 3.11 oder was? So etwas ist Aufgabe eines Schedulers, der über diesen Diensten läuft, nicht der Dienste selber.

    Der Scheduler kann aber nicht mehr viel verteilen, wenn jeder Thread ohne pause 24h pro Tag 100% CPU-Last erzeugt.

    Ich würde mich freuen, wenn du auf die anderen Fragen von mir bzgl. den weiteren angedeuteten Strategien von dir noch antworten könntest.



  • taff schrieb:

    Und da auf der Maschine noch weitere Services laufen, kann ich mir nicht einfach 100% eines Cores schnappen.

    taff schrieb:

    Der Scheduler kann aber nicht mehr viel verteilen, wenn jeder Thread ohne pause 24h pro Tag 100% CPU-Last erzeugt.

    Also entweder arbeitest DU auf einem extrem exotischen System oder Deine Vorstellung wie Threads funktionieren ist falsch. Für die Betriebssysteme mit denen ich arbeite gilt:

    a) Natürlich kannst Du versuchen die 100% CPU Last zu schnappen, der Scheduler wird das schon richtig verteilen. Bei 8 Cores kann eh kein Thread mehr als 1/8tel der CPU Leistung belegen.

    b) Kein Thread kann mehr systemlast bekommen als der Scheduler ihm zugesteht. Nicht der Task "nimmt" sich CPU, sondern der Scheduler "gibt" sie ihm. Und der der verteilt nach Prioritäten was zur Verfügung steht.

    Ich glaube zunehmend das Du versuchst Probleme zu lösen die gar nicht existieren, bzw. die das Betriebssystem für Dich löst und dadurch hier auf Unverständnis stößt. Mir scheint Du versuchst den Task-Scheduler "nachzubauen" weil Dir nicht bewusst ist wie dieser Funktioniert.

    Daher machen (für mich) auch solche Aussagen wie: "Alle 100 ne Pause machen." einfach keinen Sinn. Statt dessen würde man einfach den Thread laufen lassen und seine Priorität eben reduzieren....



  • Der klassische Ansatz ist einfach ganz ganz viele Threads zu erzeugen. Bei 100 Threads fällt es nicht mehr so ins Gewicht, wie der Scheduler sie verteilt.

    PS: Über Multithreading mit Auslastung einzelner Cores zu argumentieren macht keinen Sinn.



  • loks schrieb:

    a) Natürlich kannst Du versuchen die 100% CPU Last zu schnappen, der Scheduler wird das schon richtig verteilen. Bei 8 Cores kann eh kein Thread mehr als 1/8tel der CPU Leistung belegen.

    Wenn mein Service 5Threads hat und es laufen noch 10 weitere Services mit je 3 Threads, naja dann komm ich nach deiner "Lösung" auf 100% CPU-Last.

    Ich finde, meine Fragestellung hat nichts damit zu tun ob ich pausieren will oder nicht. Es gibt einfach Gründe warum ich nicht in einem Rutsch das ganze durchlaufen will und wie hätte einfahc gerne erfahren wie man mittels mehreren Threads eine Abarbeitung realisiert.



  • taff schrieb:

    rapso schrieb:

    ...
    -- durchsucht die liste mit einem counter der pro element hochgezaehlt wird und bei z.B. counter==1000 -> liste unlock; sleep(100); liste lock und nochmal von vorne ueber die elemente iterieren bis der thread bei einem nicht markierten glied der liste ankommt und da weiter arbeitet.

    @taff ist etwas davon falsch?

    Ja das ist schon sehr nah an dem wie ich es habe.
    Es gibt eben dann später Thread A1 und A2
    Problem ist der sinnlose Overhead mit dem Durchlauf bis zum nicht markierten Objekt....

    denkst du nicht, dass das problem eher ist dass du zwei threads hast, aber nur _ein_ gelocktes datenset hast.
    effektiv laeuft doch immer nur ein thread waehrend der andere sleept/wartet, oder?

    das ist als ob du zwei ferraris haettest, weil du mit einem 350km/h fahren kannst, mit zweien hast du 2*350km/h. effektiv faehrst du immer nur einen.

    oder hab ich das missverstanden?

    falls dem so ist, musst du fundamental etwas aendern, und dann wirst du das jetztige problem garnicht mehr haben.



  • rapso schrieb:

    denkst du nicht, dass das problem eher ist dass du zwei threads hast, aber nur _ein_ gelocktes datenset hast.
    effektiv laeuft doch immer nur ein thread waehrend der andere sleept/wartet, oder?

    Die beiden Threads A1, A2 machen einen ReadLock auf die liste und dann wird das Listenelement an sich noch gelockt --> somit kann sich der andere thread auch durch die liste bewegen.

    Ich kann mir auch genau so gut vorstellen, dass ich auch ständig eine queue fülle und diese abarbeite



  • 100% CPU-Last

    Ich sehe da kein Problem an sich. Der Scheduler des Betriebssystems sollte Rechenzeit gerecht verteilen. Ist fuer den Thread keine Arbeit vorhanden, dann gibt es geeignete Synchronisationsmechanismen.

    Und da auf der Maschine noch weitere Services laufen, kann ich mir nicht einfach 100% eines Cores schnappen.
    Auch andere Threads können auf diese Datenstruktur zugreifen

    Fuer den Schutz von Datenstrukturen vor nebenlaeufigem Zugriff existieren geeignete Synchronisationsmechanismen. Schlafen ist in den meisten Faellen ungeeignet.

    Ja ein Grund ist, dass ich immer wieder zurückkehre ist, dass der Abbruch des Threads nur in der Thread-Schleife passieren sollte und nicht in anderen Strukturen

    Ist normalerweise kein Problem. Beispielsweise kann von ausserhalb ein "stop"-Flag gesetzt werden, dass innerhalb des Threads abgefragt wird.

    Das hört sich schon interessanter an

    Nun, anscheinend bist du Anfaenger in Bezug auf parallele Programmierung.

    Grundsätzlich hätte ich gerne div. Lösungwege gelesn oder ob es hier so eine Art Design-Patterns auch für ständiges paralleles Abarbeiten von Listen gibt

    Ja, gibt es. Welche Buecher/Artikel/Tutorials hast du dir schon angesehen?



  • taff schrieb:

    rapso schrieb:

    denkst du nicht, dass das problem eher ist dass du zwei threads hast, aber nur _ein_ gelocktes datenset hast.
    effektiv laeuft doch immer nur ein thread waehrend der andere sleept/wartet, oder?

    Die beiden Threads A1, A2 machen einen ReadLock auf die liste und dann wird das Listenelement an sich noch gelockt --> somit kann sich der andere thread auch durch die liste bewegen.

    also arbeitet entweder
    thread A drauf und thread B gammelt
    oder
    Thread B drauf und thread A gammelt
    ?

    Ich kann mir auch genau so gut vorstellen, dass ich auch ständig eine queue fülle und diese abarbeite

    1. du muestest uns/mir mal beschreiben was du eigentlich machst bzw vor hast.
    soweit ich sehe hast du:
    - ein set von daten
    - fuer jeden eintrag soll "GemeindePruefung" aufgerufen werden
    - das datenset wir an sich bearbeitet (was genau? sortiert? fuegst du was hinzu? entfernst? modifizierst?)
    - ...

    2. was macht thread B waehrend thread A die aufrufe macht? wartet der wirklich nur auf thread A dass die daten freigegeben werden? wieviel geschwindigkeitszuwachs hattest du durch das aufteilen in 2 threads erhalten?

    3. wie lange dauern die 100aufrufe von thread A? 1ms? 1s? 10s? 10min? von sowas haengt auch ab wie fein granular man die threads synchronisieren wuerde.



  • knivil schrieb:

    Fuer den Schutz von Datenstrukturen vor nebenlaeufigem Zugriff existieren geeignete Synchronisationsmechanismen. Schlafen ist in den meisten Faellen ungeeignet.

    du meinst einen lock? Ja das wird sowieso gemacht

    knivil schrieb:

    Ja ein Grund ist, dass ich immer wieder zurückkehre ist, dass der Abbruch des Threads nur in der Thread-Schleife passieren sollte und nicht in anderen Strukturen

    Ist normalerweise kein Problem. Beispielsweise kann von ausserhalb ein "stop"-Flag gesetzt werden, dass innerhalb des Threads abgefragt wird.

    Deswegen u.a. auch die unterbrechung der Abbarbeitung, weil dieses "stop" habe ich ungern in der Datenstruktur drinnen.

    knivil schrieb:

    Das hört sich schon interessanter an

    Nun, anscheinend bist du Anfaenger in Bezug auf parallele Programmierung.

    Ich habe nie was anderes behauptet, oder?

    knivil schrieb:

    Grundsätzlich hätte ich gerne div. Lösungwege gelesn oder ob es hier so eine Art Design-Patterns auch für ständiges paralleles Abarbeiten von Listen gibt

    Ja, gibt es. Welche Buecher/Artikel/Tutorials hast du dir schon angesehen?

    ich kenne eigentlich nur die 0815-Patterns (factory, singleton, adapter, usw.), aber ev. könntest du mir Tipps in diesem Bereich für paralles Abarbeiten geben?

    rapso schrieb:

    taff schrieb:

    rapso schrieb:

    denkst du nicht, dass das problem eher ist dass du zwei threads hast, aber nur _ein_ gelocktes datenset hast.
    effektiv laeuft doch immer nur ein thread waehrend der andere sleept/wartet, oder?

    Die beiden Threads A1, A2 machen einen ReadLock auf die liste und dann wird das Listenelement an sich noch gelockt --> somit kann sich der andere thread auch durch die liste bewegen.

    also arbeitet entweder
    thread A drauf und thread B gammelt
    oder
    Thread B drauf und thread A gammelt
    ?

    Nein, warum sollte ein Thread gammeln? Mittels dem Readlock können beide Threads auf die Vectoren zugreifen und der Zugriff auf das Daten-Objekt (=Gemeinde) wird mittels TryWriteLock gemacht und somit blockiert mich auch nicht der andere Thread beim Durchlauf.

    rapso schrieb:

    Ich kann mir auch genau so gut vorstellen, dass ich auch ständig eine queue fülle und diese abarbeite

    1. du muestest uns/mir mal beschreiben was du eigentlich machst bzw vor hast.
    soweit ich sehe hast du:
    - ein set von daten
    - fuer jeden eintrag soll "GemeindePruefung" aufgerufen werden
    - das datenset wir an sich bearbeitet (was genau? sortiert? fuegst du was hinzu? entfernst? modifizierst?)
    - ...

    2. was macht thread B waehrend thread A die aufrufe macht? wartet der wirklich nur auf thread A dass die daten freigegeben werden? wieviel geschwindigkeitszuwachs hattest du durch das aufteilen in 2 threads erhalten?

    3. wie lange dauern die 100aufrufe von thread A? 1ms? 1s? 10s? 10min? von sowas haengt auch ab wie fein granular man die threads synchronisieren wuerde.

    ad1)
    - Für jede Gemeinde wird eine Prüfung gemacht (nur für diesen benötige ich Thread A1 & A2)
    - Die Gemeinde kann einem anderen Bundesland zugewiesen gelöscht oder neu angelegt werden.
    - Die Gemeinde daten werden auch aktualisiert

    ad2) Wie vorhin beschrieben wartet Thread A nicht auf B. Die Überprüfung aller Daten ist nun ca. um 35% schneller (statt 10sec nun 6-7sec)

    ad 3) Das kann man so nicht sagen, weil 100 Überprüfungen können 50msec sein, aber auch einmal 100msec.

    Wie gesagt geht es mir nicht darum, dass ich es nicht nicht funktioniert, sondern wie ich das ganze optimal löse ohne unnötigen overhead (überspringen der schon überprüften Gemeinden, etc.)



  • taff schrieb:

    rapso schrieb:

    taff schrieb:

    rapso schrieb:

    denkst du nicht, dass das problem eher ist dass du zwei threads hast, aber nur _ein_ gelocktes datenset hast.
    effektiv laeuft doch immer nur ein thread waehrend der andere sleept/wartet, oder?

    Die beiden Threads A1, A2 machen einen ReadLock auf die liste und dann wird das Listenelement an sich noch gelockt --> somit kann sich der andere thread auch durch die liste bewegen.

    also arbeitet entweder
    thread A drauf und thread B gammelt
    oder
    Thread B drauf und thread A gammelt
    ?

    Nein, warum sollte ein Thread gammeln?

    das war meine initialle kristalkugelleserei die du mit "ja" beantworte hattest 😉

    Mittels dem Readlock können beide Threads auf die Vectoren zugreifen und der Zugriff auf das Daten-Objekt (=Gemeinde) wird mittels TryWriteLock gemacht und somit blockiert mich auch nicht der andere Thread beim Durchlauf.

    das problem ist aber, dass der trywritelock nur erfolgreich ist, wenn du die Thread A0, A1... regelmaessig (also nach 100iterationen) unlocken laesst und die dann ne zeitlang 'gammeln' ?

    rapso schrieb:

    Ich kann mir auch genau so gut vorstellen, dass ich auch ständig eine queue fülle und diese abarbeite

    1. du muestest uns/mir mal beschreiben was du eigentlich machst bzw vor hast.
    soweit ich sehe hast du:
    - ein set von daten
    - fuer jeden eintrag soll "GemeindePruefung" aufgerufen werden
    - das datenset wir an sich bearbeitet (was genau? sortiert? fuegst du was hinzu? entfernst? modifizierst?)
    - ...

    2. was macht thread B waehrend thread A die aufrufe macht? wartet der wirklich nur auf thread A dass die daten freigegeben werden? wieviel geschwindigkeitszuwachs hattest du durch das aufteilen in 2 threads erhalten?

    3. wie lange dauern die 100aufrufe von thread A? 1ms? 1s? 10s? 10min? von sowas haengt auch ab wie fein granular man die threads synchronisieren wuerde.

    ad1)
    - Für jede Gemeinde wird eine Prüfung gemacht (nur für diesen benötige ich Thread A1 & A2)
    - Die Gemeinde kann einem anderen Bundesland zugewiesen gelöscht oder neu angelegt werden.
    - Die Gemeinde daten werden auch aktualisiert

    ad2) Wie vorhin beschrieben wartet Thread A nicht auf B.

    wenn Thread A staendig auf den daten arbeiten mittels readlock, wie koennte thread B jemals drankommen mit dem trywritelock? doch nur indem thread A ab und zu pausiert um zu warten dass thread B eine chance bekommt, oder?

    Die Überprüfung aller Daten ist nun ca. um 35% schneller (statt 10sec nun 6-7sec)

    ad 3) Das kann man so nicht sagen, weil 100 Überprüfungen können 50msec sein, aber auch einmal 100msec.

    Wie gesagt geht es mir nicht darum, dass ich es nicht nicht funktioniert, sondern wie ich das ganze optimal löse ohne unnötigen overhead (überspringen der schon überprüften Gemeinden, etc.)

    mein vorschlag:
    ein einziges simples lock fuer das array
    jeglicher thread der traversiert muss das lock halten
    die "A"s markieren dabei das element das sie bearbeiten mit einem 'lock' was nicht atomic sein muss da sie ja schon das globale lock halten. und in dem moment lassen sie das lock auch schon los und merken sich nur den index an dem sie sind.
    wenn "A"s fertig sind (was deiner angabe ca einmal pro ms passiert), nehmen sie sich das lock wieder, 'unlocken' ihr element, traversieren eins weiter und locken das element und lassen das globale lock wieder los.
    "B" kann sich das lock nun viel oefter schnappen, denn thread "A" haelt es nur microsekunden waehrend der traversierung, also ca 0.1% der zeit und thread "B" kann elemente vertauschen, sofern sie nicht selbst gelockt sind. Da thread "A" nur einen index hat, darf der vector der elemente (das muessen natuerlich pointer vector sein) frei vertauschen usw.

    ich nehme jetzt mal an die reihenfolge der elemente ist nicht wichtig und thread A iteriert eh im loop ueber alles, sodass es nicht tragisch ist, dass es eine kleine chance gibt ein element mal in einem loop durchgang nicht zu erwischen.

    auf diese weise hast du kaum synchronizations overhead zwischen den threads, du koenntest von thread "A" einige erstellen die vor sich hin arbeiten und haettest eine relativ lineare performance skalierung. (bis du keine cores mehr frei hast)


Anmelden zum Antworten