Multithreading -> Instabilere Programme?



  • naja schrieb:

    Einfach nur Task statt Thread zu sagen hilft da nicht viel.

    Du hast nichts von dem verstanden was ich gesagt habe 😞



  • 'threads' sind ja diese dinger, mit denen man manuell die CPU-ressourcen aufteilt. diese, rein technische sichtweise des händischen und statischen zerstückelns von rechenzeit, ist wohl das, was du (shade'o'mine), mit dem begriff 'task' abmildern willst. nenn' es doch 'prozess'. so wird's z.b. im umfeld von hardwarebeschreibungssprachen genannt. da ist es gang und gebe, dass sich viel paralleles und nebenläufiges zeug abspielt (was für die denke reiner softwerker, mit ihren auf sequentiellen code ausgelegten programmiersprachen, erstmal eine grosse hürde ist).
    🙂



  • Dann bring doch mal ein Beispiel was der Unterschied zwischen Task und Thread sein soll und was dann besser und einfacher ist.

    So einfach wie bei Hardware kleinste Teile parallel ablaufen lassen geht halt bei Software nicht einfach mit ner Lib. Da brauchst du schon mal Unterstützung vom Betriebssystem und obs dann einfach geht bin ich mir auch nicht sicher.



  • concurrent-freak schrieb:

    'threads' sind ja diese dinger, mit denen man manuell die CPU-ressourcen aufteilt. diese, rein technische sichtweise des händischen und statischen zerstückelns von rechenzeit, ist wohl das, was du (shade'o'mine), mit dem begriff 'task' abmildern willst. nenn' es doch 'prozess'. so wird's z.b. im umfeld von hardwarebeschreibungssprachen genannt. da ist es gang und gebe, dass sich viel paralleles und nebenläufiges zeug abspielt (was für die denke reiner softwerker, mit ihren auf sequentiellen code ausgelegten programmiersprachen, erstmal eine grosse hürde ist).
    🙂

    Task ist das englische Wort fuer Prozess. Nenn es halt Prozess - Namen sind Schall und Rauch.

    Frueher hat man nur von Taks gesprochen - Threads sind relativ neu. Damals hatte man schon interessante Systeme aber die Tasks im Sinne von ParallelFX sind keine Tasks im Sinne von Prozessen. Ich wuerde es eher mit Aufgaben uebersetzen. In gewissem Sinne sind sie leichgewichtige Prozesse.

    Es geht dabei darum grosse Arbeitsschnitte in kleine zu zerlegen. Wenn man mit funktionalen Sprachen zu tun hatte, dann wird man das eher verstehen. Jede Aufgabe fuer sich ist eine abgeschlossene Einheit - eben eine Funktion im funktionalen Sinn. Eine Aufgabe hat Input und produziert Output und das ganze ohne Abhaengigkeiten untereinander. Die schwierigkeit ist eben zu garantieren dass diese Abhaengigkeiten nicht bestehen. Da steckt man aktuell fest.

    Wenn man nun aber eine handvoll Aufgaben generieren kann - was oft sehr einfach ist - manchmal aber enorm schwer - dann kann das vom System problemlos parallelisiert werden. Wobei eine Aufgabe nichts mit einem Thread zu tun hat. Das ganze kann komplett seriell ablaufen - das ist den Tasks egal. Meistens will man auch nicht 1 Thread pro Task haben. Man will 100 und mehr Tasks pro Thread haben.

    Sehen wir uns einmal an was ein Task, eine Aufgabe eigentlich ist:

    vector<Image> images;
    fill(images);
    //wir haben nun eine menge bilder in unserem vector
    //jetzt wollen wir die bilder analysieren und alle bilder
    //mit bestimmten merkmalen naeher betrachten und den
    //rest wegwerfen
    copy_if(images.begin(), images.end(), out.begin(), foo);
    //und nun die bilder transformieren
    apply(out.begin(), out.end(), bar);
    

    Das ganze ist 100% parallelisierbar aber der Aufwand das wirklich zu parallelisieren ist enorm. Denn fuer jedes der 100.000 Bilder einen Thread erstellen waere Schwachsinn, also erstellen wir einfach soviele Threads wie wir CPU Kerne haben. Und schon haben wir wieder ein Problem: je nachdem wie gross ein Bild ist, desto laenger dauert es das Bild zu bearbeiten. Wir brauchen also Load Balancing Algorithmen.

    Dann muessen wir uns um das locken beim merge kuemmern und wir sind rasch auf ueber 100 Zeilen oben.

    Wir brauchen also definitiv libraries die uns diese Parallelisierungsarbeit abnehmen. Komplett automatisiert koennen diese Tools natuerlich nicht arbeiten - irgendwo muss der Programmierer schon noch selber agieren und sagen was parallelisierbar ist und was nicht.

    Indem wir aber in solchen Tasks denken (ob das sinnvoll ist oder nicht wird die Zeit zeigen - im Moment stehen wir am Anfang) koennen wir parallelisierung leicht ermoeglichen.

    foo und bar koennen jeweils problemlos zu einem Task werden. Und ein Task kann natuerlich selber aus Tasks bestehen. bar verwendet zB fuer jeden Pixel einen eigenen Task. Ist ja ganz einfach moeglich:

    Parallel.ForEach(image.getPixel(), p => { p=transform(p) });
    

    Das wichtige dabei: wir haben den Code parallelisiert. Nicht zu 100% denn foo und transform koennen uU noch parallelisiert werden - aber es ist ein Anfang. Und vorallem: mit kaum Aufwand von uns als Programmierer.

    Wenn wir in Threads denken wuerden, waere eine parallelisierung hier nur mit riesen Aufwand moeglich. Wenn wir aber in Tasks denken, ist das ganze kein Problem mehr. Oder besser gesagt: nicht mehr unser Problem sondern dass der ParallelFX Entwickler.

    uU ist dieser Ansatz in Tasks zu denken problematisch und wir sind in ein paar Jahren darueber hinaus. uU ist ParallelFX vom Ansatz her komplett falsch. Aber irgendetwas in diese Richtung brauchen wir. Oder mal ganz ehrlich: wer von euch programmiert gerne Multithreaded Systeme und vorallem: wer debugt sie gerne?

    Threads sind nicht die Antwort und IMHO ist der naechste Schritt eben Aufgaben/Tasks. Wobei X Tasks in Y Threads ablaufen. Indem wir einfach garantieren dass ein Task keine Seiteneffekte hat sparen wir uns komplett das locking.

    Natuerlich kann man immernoch mist bauen - aber das wiederhole ich ja auch oft genug: die Tools koennen (noch) nicht garantieren dass ein Task keine Seiteneffekte hat die andere Tasks beeinflussen. Aber wenn wir uns Haskell und aehnliche Sprachen ansehen -> gerade bei kleinen Funktionen ist es leicht ohne Seiteneffekte auszukommen. In den meisten Faellen ist es also kein Problem einen Task zu schreiben der keine Seiteneffekte hat.



  • Am coolsten waere es doch wenn man (man Java Beispiel) einfach eine Anotation schreiben wuerde und mir der Jit Compiler die Methode parallelisiert.

    class Foo
    {
        @parallel
        void foo() {}
    
        @parallel
        void bar() {}
    }
    

    Vielleicht auch die ganze Klasse als @parallel markieren und alles was da drinner berechnet wird kann der Jit Compiler parallelisieren. Ich als Programmierer muss dann halt dafuer garantieren das die Klasse/Methoden keine Seiteneffekte haben.

    Noch cooler waere sowas wie "const-correctness" in C/C++, nur eben eine "parallelisierbar-correctness", also das der Compiler ueberpruefen kann das der Code keine Seiteneffekte hat.

    Aber kann man eigentlich C++/Java so ummodeln, dass der Compiler immer annimmt das es keine Seiteneffekte gibt, ausser man sagt explizit das es welche gibt? Man tauscht einfach den Compiler aus und fuer ein neues keyword "siteeffect" ein, das angibt das der Code Seiteneffekte hat.



  • Ok, Tasks sollen also viele kleine Aufgaben sein, die dann die Lib auf ein paar Threads verteilt und somit das Skalieren übernimmt.

    Shade Of Mine schrieb:

    Wenn man nun aber eine handvoll Aufgaben generieren kann - was oft sehr einfach ist - manchmal aber enorm schwer - dann kann das vom System problemlos parallelisiert werden. Wobei eine Aufgabe nichts mit einem Thread zu tun hat. Das ganze kann komplett seriell ablaufen - das ist den Tasks egal. Meistens will man auch nicht 1 Thread pro Task haben. Man will 100 und mehr Tasks pro Thread haben.

    Glaub ich nicht, ich denke in den meisten Fällen ist es extrem schwer solche Tasks zu definieren, die dann beliebig verteilt werden können, vorallem, wenn sie klein sein sollen.

    vector<Image> images;
    fill(images);
    //wir haben nun eine menge bilder in unserem vector
    //jetzt wollen wir die bilder analysieren und alle bilder
    //mit bestimmten merkmalen naeher betrachten und den
    //rest wegwerfen
    copy_if(images.begin(), images.end(), out.begin(), foo);
    //und nun die bilder transformieren
    apply(out.begin(), out.end(), bar);
    

    Das ganze ist 100% parallelisierbar aber der Aufwand das wirklich zu parallelisieren ist enorm. Denn fuer jedes der 100.000 Bilder einen Thread erstellen waere Schwachsinn, also erstellen wir einfach soviele Threads wie wir CPU Kerne haben. Und schon haben wir wieder ein Problem: je nachdem wie gross ein Bild ist, desto laenger dauert es das Bild zu bearbeiten. Wir brauchen also Load Balancing Algorithmen.

    Dann muessen wir uns um das locken beim merge kuemmern und wir sind rasch auf ueber 100 Zeilen oben.

    Bei 100000 Bildern würde ich es so machen, dass ich einfach gleich viele Bilder auf jeden Thread verteile. Bei 4 Kernen also 25000 Bilder pro Thread. Musst nur die Bilder so sortieren, dass jeder Thread die gleiche Datenmenge bekommt, also jeder bekommt gleich viele große, mittlere und kleine Bilder.

    vector<Image> images;
    fill(images);
    distribute(images); //gleichmäßig verteilen
    int numCores=GetNumCores();
    int numImages = images.size();
    int imagesPerThread = numImages / numCores + 1;
    std::vector<Thread> threads;
    for(int t = 0; t<numCores; t++) {
    	int begin = imagesPerThread*t;
    	int end = imagesPerThread*(t+1)<numImages ? imagesPerThread*(t+1) : numImages;
    	threads.push_back(StartThread(begin, end, images);
    }
    WaitFor(threads);
    
    WorkThread(int begin, int end, vector<Image>& images) {
    	for(int i = begin, i<end; i++) {
    		if(foo(images[i]) {
    			apply(images[i]);
    		}
    	}
    }
    

    Da brauch ich nichts locken oder mergen und hab auch keine 100 Zeilen.

    Gut, das war jetzt ein einfaches Beispiel und die Images sind sozusagen die Tasks und die Lib könnte das mit dem verteilen auf die Cores übernehmen, wird hier keinen Geschwindigkeitsunterschied machen.

    Aber meistens hast du halt nicht 100000 Datenpakete, bei denen es so einfach ist diese zu verteilen.

    Das hier

    Parallel.ForEach(image.getPixel(), p => { p=transform(p) });
    

    geht nicht so einfach. Wenn dein transform nicht gerade eine einfache Spiegelung oder 90° Drehung ist, brauchst du immer die benachbarten Pixel. Und außerdem würde es dir den ganzen CPU Cache kaputt machen, wenn du nicht mehr durch ein Pixels Array wanderst, sondern durch ein Tasks Array und dann immer wieder ein paar Pixels holst. Da wirst du bei einem Thread durch den ganzen Tasks Overhead wahrscheinlich um mehr als das doppelte langsamer. Wenn du ein Bild mit mehreren Threads bearbeiten willst, musst du dir schon mehr überlegen, damit du nicht durch irgendwelche Seiteneffekte wieder alles langsamer machst.

    100000 große unabhängige Tasks auf mehrere Threads zu verteilen ist nicht das große Problem, egal ob mit oder ohne Lib. Aber einfach zu hoffen, dass das mit jeder Schleife funktioniert wird nicht gehen. Die Tasks Idee funktioniert gut bei Tasks die die richtige größe haben, aber solche zu finden ist meistens nicht so einfach.



  • naja schrieb:

    Bei 100000 Bildern würde ich es so machen, dass ich einfach gleich viele Bilder auf jeden Thread verteile. Bei 4 Kernen also 25000 Bilder pro Thread. Musst nur die Bilder so sortieren, dass jeder Thread die gleiche Datenmenge bekommt, also jeder bekommt gleich viele große, mittlere und kleine Bilder.

    Und genau damit bist du schonmal deutlich langsamer als ich mit ParallelFX. Du ignorierst hier viele Sachen die Performance relevant sind. zB wenn du Pech hast, bist du keinen deut schneller als wenn du es seriell ausfuehrst weil alle grossen Bilder in einem Thread landen und die anderen nur ganz kleine bekommen.

    Was wenn du ein paar Kerne nicht nutzen kannst - dann hast du sinnlos viele Context Switche.

    Der Code ist tragbar so wie er ist, aber gut ist er nicht. Und er funktioniert nur zufaellig, weil du die images inplace bearbeiten kannst - ich habe aber extra noch ein copy_if ins Beispiel dazu genommen wo du es nicht mehr schaffst.

    Aber meistens hast du halt nicht 100000 Datenpakete, bei denen es so einfach ist diese zu verteilen.

    Fast alle Schleifen sind so reduzierbar. Nicht alle, aber viele. Das zB mal als Ansatz.

    Das hier

    Parallel.ForEach(image.getPixel(), p => { p=transform(p) });
    

    geht nicht so einfach. Wenn dein transform nicht gerade eine einfache Spiegelung oder 90° Drehung ist, brauchst du immer die benachbarten Pixel. Und außerdem würde es dir den ganzen CPU Cache kaputt machen, wenn du nicht mehr durch ein Pixels Array wanderst, sondern durch ein Tasks Array und dann immer wieder ein paar Pixels holst.

    Klar geht das nicht immer, aber den Cache mache ich mir nicht kaputt - dafuer habe ich ja die Library die hier eben das Aufteilen der Pixel an die einzelnen Threads uebernimmt. Natuerlich ist der Overhead groesser als wenn ich es sequentiell mache - aber das ist immer der Fall wenn ich mehrere Kerne nutze.

    Wenn ich die Nachbar Pixel brauche - ist das hier uebrigens auch kein Thema - ich muss dann eben ein neues Bild erstellen und kann nicht inplace die Pixel aendern - aber ich habe ja lesezugriff auf das komplette original Bild.

    100000 große unabhängige Tasks auf mehrere Threads zu verteilen ist nicht das große Problem, egal ob mit oder ohne Lib. Aber einfach zu hoffen, dass das mit jeder Schleife funktioniert wird nicht gehen. Die Tasks Idee funktioniert gut bei Tasks die die richtige größe haben, aber solche zu finden ist meistens nicht so einfach.

    Und genau da erkennt man, dass du dich damit nicht tiefer beschaeftigt hast. Natuerlich kann ich die Tasks _irgendwie_ verteilen - aber bei so simplen Sachen wie dem copy_if haengt man schon mal etwas rum. Und dein images Code ist auch recht lahm und klappt nur weil du inplace operieren kannst - sobald du Daten nach aussen schreiben musst haengst du komplett.

    Natuerlich kann man einen load balancer schreiben und den verwenden, und dann eben alles inplace machen - doch wozu? du wirst mit grosser wahrscheinlichkeit langsamer sein als parallelfx und weit aus weniger flexibel.

    Genau fuer soetwas gibt es libraries - und wenn ParallelFX eine opensource Loesung fuer C++ waere, wuerden wir diese Diskussion nicht fuehren 😉

    Eine kleine Denkaufgabe da es ja so trivial ist:
    kannst du mir mal kurz ein std::unique fuer beliebige Kerne implementieren?

    Das fiese ist naemlich wenn du ploetzlich nicht mehr dumm partitionieren kannst und intelligente algos brauchst. Denn gleiche Items muessen ploetzlich in dem selben Thread landen...

    Es hat schon seinen Grund warum in der Library eine Menge Mann-Jahre stecken und es erst langsam verwendbar wird. Weil es eben _nicht_ trivial ist.



  • Shade Of Mine schrieb:

    naja schrieb:

    Bei 100000 Bildern würde ich es so machen, dass ich einfach gleich viele Bilder auf jeden Thread verteile. Bei 4 Kernen also 25000 Bilder pro Thread. Musst nur die Bilder so sortieren, dass jeder Thread die gleiche Datenmenge bekommt, also jeder bekommt gleich viele große, mittlere und kleine Bilder.

    Und genau damit bist du schonmal deutlich langsamer als ich mit ParallelFX. Du ignorierst hier viele Sachen die Performance relevant sind. zB wenn du Pech hast, bist du keinen deut schneller als wenn du es seriell ausfuehrst weil alle grossen Bilder in einem Thread landen und die anderen nur ganz kleine bekommen.

    Aber meistens hast du halt nicht 100000 Datenpakete, bei denen es so einfach ist diese zu verteilen.

    Fast alle Schleifen sind so reduzierbar. Nicht alle, aber viele. Das zB mal als Ansatz.

    Das hier

    Parallel.ForEach(image.getPixel(), p => { p=transform(p) });
    

    geht nicht so einfach. Wenn dein transform nicht gerade eine einfache Spiegelung oder 90° Drehung ist, brauchst du immer die benachbarten Pixel. Und außerdem würde es dir den ganzen CPU Cache kaputt machen, wenn du nicht mehr durch ein Pixels Array wanderst, sondern durch ein Tasks Array und dann immer wieder ein paar Pixels holst.

    Klar geht das nicht immer, aber den Cache mache ich mir nicht kaputt - dafuer habe ich ja die Library die hier eben das Aufteilen der Pixel an die einzelnen Threads uebernimmt. Natuerlich ist der Overhead groesser als wenn ich es sequentiell mache - aber das ist immer der Fall wenn ich mehrere Kerne nutze.

    Wenn ich die Nachbar Pixel brauche - ist das hier uebrigens auch kein Thema - ich muss dann eben ein neues Bild erstellen und kann nicht inplace die Pixel aendern - aber ich habe ja lesezugriff auf das komplette original Bild.

    Hast du schonmal einen Algorithmus zum Beareiten von Bildern geschrieben? Mit separierbaren Filtern usw. gearbeitet? Diese Lib müsste zaubern können, wenn die das alles kann, was du da beschreibst. Natürlich brauchst du ein zweites Bild in das du die Daten schreibst. Du gehst z.B. eine Zeile des Bildes durch und nimmst vom linken, rechten und aktuellen Pixel den Farbwert und schreibst den Mittelwert in das Zielbild. Jetzt gehst du ein Pixel weiter und hast mit extrem großer wahrscheinlichkeit dieses Pixel und das linke im Cache, weil du vor ein paar Operationen darauf zugegriffen hast. Generiert mir die Lib ein Codestück das dann abgearbeitet wird ohne wieder zurück zu den Tasks zu springen? Wenn du immer wieder zum Task zurück springst und dann wieder ein Pixel bearbeitest hast du mit sehr großer wahrscheinlichkeit doppelt soviele oder mehr Cache Misses wie ohne. Erklär mir doch mal wie das Schritt für Schritt ablaufen soll ohne das die ganzen Cache Misses auftreten.

    100000 große unabhängige Tasks auf mehrere Threads zu verteilen ist nicht das große Problem, egal ob mit oder ohne Lib. Aber einfach zu hoffen, dass das mit jeder Schleife funktioniert wird nicht gehen. Die Tasks Idee funktioniert gut bei Tasks die die richtige größe haben, aber solche zu finden ist meistens nicht so einfach.

    Und genau da erkennt man, dass du dich damit nicht tiefer beschaeftigt hast. Natuerlich kann ich die Tasks _irgendwie_ verteilen - aber bei so simplen Sachen wie dem copy_if haengt man schon mal etwas rum. Und dein images Code ist auch recht lahm und klappt nur weil du inplace operieren kannst - sobald du Daten nach aussen schreiben musst haengst du komplett.

    Wenn ich nach außen schreibne muss, dann geht das ohne lib genauso wie mit. Wenn ich dabei locken muss, dann kann das die Lib auch nicht wegzaubern.



  • Es ist langweilig - du ignorierst die Punkte die du nicht widerlegen kannst und streitest dann um die Grenzfragen. Es gibt nunmal ueberall Grenzfragen aber worum es geht sind die Kernfragen - und da du diese nicht anfasst nehme ich mal an dass du sie nicht widerlegen kannst 😉 Das reicht mir.

    Und implementiere mir einfach mal ein copy_if und ein unique mit Threads und ich zeig dir dann in einer Zeile Code wie ich es machen wuerde und wette dass die Performance von meiner einen Zeile Code deutlich schneller ist als das was du produziert hast.

    Genau fuer soetwas hat man Libraries.



  • Shade Of Mine schrieb:

    Es ist langweilig - du ignorierst die Punkte die du nicht widerlegen kannst und streitest dann um die Grenzfragen. Es gibt nunmal ueberall Grenzfragen aber worum es geht sind die Kernfragen - und da du diese nicht anfasst nehme ich mal an dass du sie nicht widerlegen kannst 😉 Das reicht mir.

    Naja, Du hältst dich ja auch nur bei den spielzeugbeispielen auf. Wie parallelisierst Du denn automatisch das Filteranwenden auf ein Bild? Woher weiß die Library wie das Bild im Speicher liegt und wie man daher am geschicktesten die Aufteilung wählt, ohne sich viel mehr Cache-Misses einzufangen. Oder beispielsweise eine Matrixmultiplikation. Die sequenzielle Schleife lässt sich sehr leicht hinschreiben. Wenn man das naiv parallelisiert (und was soll die Library anderes tun) kriegt man bei einer nxn-Matrix O(n) Cache-misses pro Element.

    Dass Du die Probleme nicht anerkennst heißt nicht, dass sie nicht existieren.
    Natürlich ist es ein netter Ansatz sowas wie for_each mit automatischem Load-Balancing anstoßen zu können. Aber damit lassen sich eben viele Probleme nicht lösen.



  • Jester schrieb:

    Naja, Du hältst dich ja auch nur bei den spielzeugbeispielen auf. Wie parallelisierst Du denn automatisch das Filteranwenden auf ein Bild? Woher weiß die Library wie das Bild im Speicher liegt und wie man daher am geschicktesten die Aufteilung wählt, ohne sich viel mehr Cache-Misses einzufangen. Oder beispielsweise eine Matrixmultiplikation. Die sequenzielle Schleife lässt sich sehr leicht hinschreiben. Wenn man das naiv parallelisiert (und was soll die Library anderes tun) kriegt man bei einer nxn-Matrix O(n) Cache-misses pro Element.

    Der Programmierer muss diese Tasks erstellen - daran fuehrt kein Weg vorbei. Aber ich wiederhole mich.

    Deshalb nur noch einmal:
    Es geht darum in Tasks zu denken und nicht in Threads.

    Das ist mein Punkt. Viele Probleme lassen sich so recht leicht parallelisieren - eben weil sie sowieso nur aus Tasks bestehen. Ich hatte zB letztens eine Bildverarbeitung wo mir diese Parallelisierung enorme Runtime ersparnisse gebracht haette.

    Ich habe _nie_ behauptet es geht immer und ich habe wohl oft genug erwaehnt dass wir uns am _anfang_ befinden und dass diese Libraries gerade jetzt erst nutzbar werden.

    Dass Du die Probleme nicht anerkennst heißt nicht, dass sie nicht existieren.
    Natürlich ist es ein netter Ansatz sowas wie for_each mit automatischem Load-Balancing anstoßen zu können. Aber damit lassen sich eben viele Probleme nicht lösen.

    Ich habe nie davon gesprochen dass _alles_ moeglich ist. Ich habe gesagt dass viel jetzt direkt sofort parallelisierbar ist. Und das sage ich nachdem ich durch x beliebigen Code von mir durchschaue: die meisten Schleifen sind parallelisierbar mit keinen bis geringem Aufwand.

    Davon geht zB auch die MCSTL aus.

    Aber ich wiederhole es nochmal gerne:
    Wir stehen am Anfang von diesen Entwicklungen und Tasks sind vielleicht die falsche Einheit. Ich kann hier nur eins mit sicherheit sagen: die Threads wie wir sie jetzt kennen mit dem manuellen locking ist nicht die Antwort. Wir brauchen etwas anderes und aktuell ist ParallelFX der beste Ansatz den wir haben.

    Und ich fuege hinzu, dass wenn ParallelFX eine OpenSource Entwicklung fuer C++ aus der Linux/BSD Ecke waere, wir diese Diskussion nicht fuehren wuerden.

    Zu sagen ParallelFX ist durch Threads ersetzbar ist einfach katastrophal falsch. Denn es ist eben nicht durch threads ersetzbar - das ist ja eines der Design kriterien gewesen.

    Zu sagen ich kann nicht alles mit ParallelFX automatisiert parallelisieren ist irgendwie redundant. Denn wenn ich das koennte waere die Diskussion unnoetig. ParallelFX bietet die Tools damit der programmierer die Sachen parallelisieren kann. Wenn wir Algorithmen haben die nicht parallelisierbar sind, tja dann haben wir Pech gehabt. Worum es aber geht ist, dass alles was parallelisierbar ist, mit keinem bis geringem aufwand zu parallelisieren geht.



  • Ich will garkein copy_if oder unique einfach so mal parallelisieren, weil ich es einfach für Quatsch halte jeden Loop blind zu parallelisieren. Genauso wie ich nicht irgendwas optimiere ohne vorher nen Profiler zu verwenden.

    Die Lib und die Tasks Idee mag ja ganz gut sein, aber du machst die Tasks einfach zu klein. Wenn du pro Task nur 5 Operatioen Overhead hättest, aber der Task selber auch nur 20 Operationen braucht, dann erzeugst du viel zu viel Overhead. Und die Chance, dass du den Cache kaputt machst steigt bei kleinen Tasks auch an. Wenn du bei Bilder mit Millionen von Pixeln auch genauso viele Tasks machst, hast du halt viel zu viel Overhead. Wenn du für jede Bildzeile einen Task machst, könne das schon eher sinnvoll sein.



  • Wie sollten eigentlich die Tasks für ein unique aussehen? Ich kann mir da nix ohne locking vorstellen.



  • sunshineCoder schrieb:

    Wie sollten eigentlich die Tasks für ein unique aussehen? Ich kann mir da nix ohne locking vorstellen.

    hash basierte partitionierung.

    du packst alle typen die gleich sind eben in den selben thread - indem du das garantierst, kannst du wieder problemlos parallelisieren.

    natuerlich hast du dann uU ein problem wenn du sehr viele gleiche items hast - zB wenn alle items gleich sind, dann hast du seriell gearbeitet und einige zeit fuer die partitionierung geopfert.

    PS:
    bzgl cache zerstoeren:
    man arbeitet nicht auf index 1 dann auch index 100.000 dann auf index 12 dann auf index 2.000.000 sondern man kann auch auf index 1,2,3,4 gleichzeitig, danach auch 5,6,7,8 gleichzeitig arbeiten...



  • Shade Of Mine schrieb:

    sunshineCoder schrieb:

    Wie sollten eigentlich die Tasks für ein unique aussehen? Ich kann mir da nix ohne locking vorstellen.

    hash basierte partitionierung.

    du packst alle typen die gleich sind eben in den selben thread - indem du das garantierst, kannst du wieder problemlos parallelisieren.

    😕 Ich dachte Tasks sind keine Threads. Und wie stellst du fest was gleich ist? Das macht doch unique.



  • Gregor schrieb:

    sunshineCoder schrieb:

    Wird Software jetzt noch fehleranfälliger, wenn jetzt immer mehr versuchen Mulhithreading einzusetzen?

    Hi. Ja.

    Hi. Warum?



  • Shade Of Mine schrieb:

    Deswegen arbeitet man ja wie verrueckt an besseren Techniken als diese dummen ewigen locks 😉
    ParallelFX von Microsoft sieht da schon mal nicht schlecht aus.

    Alternativ kann man natuerlich auch Ansaetze wie zB Erlang verfolgen. Ueber kurz oder lang werden wir aber fuer die meisten Anwendungen von den haendischen locks wegkommen.

    Du meinst Erlang verdrängt C++?



  • Ist ParallelFX jetzt der große Erfolg?


Anmelden zum Antworten