Wie behebe ich ein großes und vermutlich bekanntes Memory Leak?

Kokujou schrieb:
was passiert eigentlich wenn in einem Thread weitere Tasks erzeugt werden, könnte das ein Problem werden?
Du meinst, du startest x Tasks aus einem Thread, dann startet jeder Thread wieder x Tasks, usw.? Das könnte den hohen Speicherverbrauch auch erklären.
Du wirst ja zumindest irgendwo eine Debug-Console oder Log-Funktion haben, in der du ausgeben kannst, wann du eine neue Berechnung startest und wann diese zu ende ist.
 
nun ich leite die gesamte ausgabe an ein externes Programm um weil der Unity Debugger ja leider blockiert wird >.> während der berechnungen schläft das programm ja komplett ein.

das ist wirklich das penetranteste Problem dass ich habe ich kann absolut nichts debuggen. Warum hängt mein Programm in einer Schleife? Keine Ahnung, weil ich absolut nichts sehe. Meine Logs helfen mir da sogut wie kaum ich kann ja schlecht für jede temporäre Variable jedes mal einen Log ausgeben.
Ergänzung ()

ich wrüde z.B. auch gerne wissen warum eine meiner KIs 80 Züge Problemlos runterrattert und ohne dass mein Memory oder CPU Limit ereicht ist plötzlich einfriert.
Nach einem Zug? Kein Problem. Aber nach 80 erfolgreichen Spielen? das nenn ich mal einen "Blinker" >.>
 
Ohne debugmöglichkeit und ohne Code geht natürlich nichts.
Du könntest aber eine Art Timer einbauen, der dafür sorgt das dein Algorithmus abbricht, wenn zu lange gerechnet wurde. Die KI würde dann das bis dahin errechnete beste Ergebnis nutzen. Vielleicht sogar mit Ausgaben schmücken, z.B. an welcher Stelle abgebrochen werden musste, wie viele Versuche berechnet wurden, etc.
Könnte man natürlich ausnutzen, also die KI dumm machen, indem man dem Spiel nur einen CPU-Kern zuweist.
 
Das sagt sich so leicht. Was ist das bis dahin feststehende Ergebnis?

Meine KI baut einen Zustandsbaum mit (8!) Endzuständen auf. Und das sind die VORberechnungen um überhaupt mit der Bewertung anfangen zu können. Um das Ding jetzt halbwegs performant zu kriegen schmeiße ich sinnlose Züge noch raus und nutze Multithreading, der Inhalt jedes Zustands ist auch so stark komprimiert wie nur irgendmöglich, das war übrigens eine der Zielsetzungen an meinem Projekt.

Also wenn die KI mittendrin abbricht hat sie absolut nichts mit dem sie arbeiten kann. Das eigentliche Bewerten der Züge ist noch human.
 
Ich glaube der Begriff Memory-Leak ist etwas falsch, weil C# ja durch den gc automatisch aufräumt.
Memory-Leaks kommen ja eigtl aus C/C++, wo man keine Referenz/Pointer mehr auf Objekte hat und daher dieser Speicher "verloren" ist, bis der Prozess beendet wird und das Betriebssystem aufräumt.

Daraus folgt, dass du wahrscheinlich irgendwo Pointer/Referenzen aufbewahrst, ohne, dass du das wolltest. Also zB indem du immer mehr Threads in eine Liste einfügst und die alten nicht löscht oder ähnliches.
Such mal deine Container ab, wo du kram ablegst..

Oder google mal "c# size of variable in memory" und beobachte, was dort genau steigt.

Ansonsten hat Unity auch einen Profiler, der RAM-Verbrauch über Zeit anzeigt. Mich würde sehr wundern, wenn man dort nicht Objektweise aufgeschlüsselt bekommt, wo der RAM hingeht.
 
Zuletzt bearbeitet:
Kokujou schrieb:
sagtmal... wie kann so ein Problem überhaupt auftreten?
Das nennt sich Bug im Programmcode. Nicht alle Bugs sind reine Syntax-Fehler oder 'Division von zwei Ints wo man eigentlich ein Double raus haben wollte'.

Deine High-Level Beschreibungen werden dir nicht weiter helfen und auch die grobe Vorstellung davon, in welchem Code-Teil das ganze zu finden wird reicht nicht um das ganze zu beheben.
 
Ja man hat einen Profiler aber der ist nur für normale Aktivität und läuft auf dem Unity Main-Thread.

da ich den Mainthread sowie alle anderen Threads durch mein Multithreading blockiere und meinen Prozessor zu 100% mit den rechenaufgaben belege ist es relativ schwer im laufenden Betrieb einen fehler zu finden...

Und ich sag nicht den ungefähren Code-Teil, ich kenne die Datenstruktur die es verursacht. Diese Datenstruktur wird aber, und da bin ich mir zu 100% sicher, nur ein einziges Mal erzeugt.

Ich verwende explizit nichtmal Threads sondern nutze nur einmal die Parallel.For Schleife. In der For-Schleife gibt es eine temporäre Variable die meine Datenstruktur enthält. ALLE. Daten. Dort liegt 99% meiner gesamten Memory und die wird am Ende der Funktion sowohl implizit als auch explizit aufgeräumt.

Am ende der Iteration setze ich nämlich sogar manuell = 0.

die einzige noch übrige erklärung ist dass aus irgendeinem Grund ohne die nötige Spezifikation immer mehr Threads durch die Parallel.For angehäuft werden und diese nicht parallel sondern asynchron laufen. Was grundsätzlich wünschenswert aber in meinem speziellen Fall natürlich großer Mist ist da so alle "gleichzeitig" laufen, aber keiner beendet wird.

so würde ich mir das erklären. Ich glaube dieser MaximumDegreeOfParallelism hat etwas geholfen....

Und ich nehme an seitens microsoft ist das auch gewollt da man ja eigentlich nicht davon ausgeht dass man so enorme Datenmengen verarbeitet wie ich und asynchronität ja grundsätzlich wünschenswert ist...

ich fände es aber schöner wenn man explizite Funktionen hat wo steht "Die ist echt-parallel", "die ist quasi-parallel" und "die macht beides."

ich hatte es schon oft dass ich Funktionen verwendet habe und die einfach NUR asynchron gelaufen sind.
 
Wo liegt denn für dich der Unterschied zwischen parallel und asynchron? Und in wie weit sollte das hier relevant sein?
 
ganz einfach. Asynchron ist wenn Threads synchron laufen, ihre ausführung aber "Unterbrechen" um andere Tasks zwischendrinnen auszuführen.

Ein beliebtes Beispiel: Du sendest nen HTTP-Request und wartest auf die Antwort. Das dauert natürlich n paar Sekunden schlimmstenfalls. Also während du wartest kannst du auf die Art einfach nen anderen Task einschieben.

Parallelität heißt du nutzt tatsächlich deine Kerne auf und lässt berechnungen ECHT parallel laufen.

(das ist übrigens nur meine persönliche interpretation, ich hab das nirgends gelesen oder so).

Parallel laufen können nur so viele Tasks wie Prozessoren da sind, also Kerne. Asynchron laufen können theoretisch unendlich viele Tasks. Du gehst da rein, machst nen Rechenschritt, gehst zu nem anderen, machst nen rechenschritt. Das ist in vielen Dingen nützlich besonders aber halt wenn man z.b. in loops verhindern will dass der ganze Main_Thread blockiert wird.

Unity z.B. nutzt es auch um Animationen abzuspielen. Wenn du die asynchron laufen lässt wird so nach jedem Berechnungsschritt in der die Figur ihre Position ändert danach der für uns unsichtbare Rendering-Part aufgerufen und die Figur wird animiert. Ohne asynchronität passiert einfach folgendes:
Figur hat Position A -> ... -> Figur hat Position B. Keine Interpolation zwischen den beiden.
 
Gut, dann hast du das verstanden.

Kokujou schrieb:
ich fände es aber schöner wenn man explizite Funktionen hat wo steht "Die ist echt-parallel", "die ist quasi-parallel" und "die macht beides."
C# hat für beides eine Lösung. Threads (oder abstrahiert mit bpsw. den Parallel-Methoden) und async/await mit den Tasks.

Kokujou schrieb:
die einzige noch übrige erklärung ist dass aus irgendeinem Grund ohne die nötige Spezifikation immer mehr Threads durch die Parallel.For angehäuft werden und diese nicht parallel sondern asynchron laufen. Was grundsätzlich wünschenswert aber in meinem speziellen Fall natürlich großer Mist ist da so alle "gleichzeitig" laufen, aber keiner beendet wird.
Parallel nutzt Threads. Und das ist alles spezifiziert. Für jedes Parallel.For werden maximal MaxDegreeOfParallelism Threads genutzt. Das ist standardmäßig -1, also "unlimited". Der Scheduler entscheidet dann selbst, wie viele Threads er startet. Parallele (oder verschachtelte) Parallel.For Aufrufe sind dabei kein Problem, da sich diese ein ThreadPool teilen.
 
Zuletzt bearbeitet:
Ich habe kein Unity und den ganzen Unity-Kram rauszulöschen ist mir zu aufwendig, daher nur so über den Code drübergeguckt.
Code:
                        newBoard = new VirtualBoard();
                        return EndGame();
Falls deine Intention war, den Leser zu verwirren, hat das funktioniert. Das soll wohl deine Variante des Speicheraufräumens sein. Hat nur leider keinen Effekt (bis auf die Verwirrung), das Objekt wird nach Verlassen der Methode automatisch aufgeräumt, da Methoden-lokal.

Echte Speicherlecks o.Ä. habe ich nicht gefunden. Du erzeugst halt viele Objekte und das braucht nun mal Speicher. Die Lösung wäre hier, Objekte wiederzuverwenden. Z.B. aus
Code:
                    for (int handID = 0; handID < aHand.Count; handID++)
                    {
                        List<Move> ToBuild = new List<Move>();
macht du
Code:
                    List<Move> ToBuild = new List<Move>(aHand.Count+1);
                    for (int handID = 0; handID < aHand.Count; handID++)
                    {
                        ToBuild.Clear();
Die Liste wird hier zum einen wiederverwendet und zudem mit dem Maximum des voraussichtlichen Inhalts initialisiert. Das verhindert ein Neuerstellen und Umkopieren des internen Arrays, wenn die Liste wächst.

Der Gebrauch von Dictionaries ist fast schon inflationär. Die haben eine riesigen Speicherverbrauch im Vergleich zu Listen und sollten daher mit Bedacht eingesetzt werden, gerade wenn du so viele Instanzen erstellst. OmniscientCards verwendet gleich 4 Stück davon, die du einfach durch je
Code:
private uint[] PPlayableMonths = new uint[12];
ersetzen könntest. (Warum eigentlich uint statt int?)
In den AI-Klassen verwendest du ebenfalls Dictionaries für weights, obwohl es sogar lokale Variablen tun würden. Wozu benutzt du gerade hier Strings als Indizes? Du hast zwar eine Methode GetWeights aber ich sehe nicht, wo du die benötigst.
Siehe auch Player.CollectedYaku.

Apropos Player. Settings.Players ist statisch und in BuildRandomBoard(), das ja parallel(!) ausgeführt wird, steht
Code:
Settings.Players = newBoard.Players;
Der Inhalt von Settings.Player ist also für die Tonne. Ich glaube fast, diese Zeile sollte da gar nicht stehen, da im weiteren Verlauf immer newBoard.Players nutzt.
 
Darlis schrieb:
Falls deine Intention war, den Leser zu verwirren, hat das funktioniert. Das soll wohl deine Variante des Speicheraufräumens sein. Hat nur leider keinen Effekt (bis auf die Verwirrung), das Objekt wird nach Verlassen der Methode automatisch aufgeräumt, da Methoden-lokal.

Jap... Da es eine Strutkur ist ist =null nicht möglich. Hat aber auch nichts gebracht.

Darlis schrieb:
Der Gebrauch von Dictionaries ist fast schon inflationär. Die haben eine riesigen Speicherverbrauch im Vergleich zu Listen und sollten daher mit Bedacht eingesetzt werden, gerade wenn du so viele Instanzen erstellst. OmniscientCards verwendet gleich 4 Stück davon, die du einfach durch je

Das ist echt gut zu wissen! Ich dachte Dictionaries sind eine gute Lösung weil sie schnellen Zugriff versprechen. Da ich auch mit starken Laufzeitproblemen zu kämpfen habe war das eine Optimierung. Die offenbar am einen Ende geholfen aber am anderen Ende geschadet hat.

Darlis schrieb:
Warum eigentlich uint statt int?)
Ich hab viele Ideen die aber alle nicht so schön funktionieren wie ich sie mir gedacht habe und einfach nicht aufgeräumt worden^^ ich sagte ja der Coding Stil ist nicht so schön, darum wollte ich euch den Anblick eigentlich ersparen.

Ich dachte mir, Herrgott ich benutze oft Zahlen die kaum ein Byte belegen. warum also nicht "kleinere" Datenstrukturen verwenden. Dass uint dasselbe ist wie int nur mit anderer Interpretation des Führungsbit weiß ich jetzt natürlich. Short oder Byte wäre eine Lösung aber das ist eigentlich völlig egal da die sowieso beim Rechnen in int gecastet werden, wie ich hörte. Und damit wirkt sich das kaum auf die Laufzeit aus - schade.

Darlis schrieb:
Du hast zwar eine Methode GetWeights aber ich sehe nicht, wo du die benötigst.
Das ist Unity-spezifische sehr unschöne ***. Ich will die Variablen im Unity-Inspektor verändern können. Also hab ich ein allgemeines Dictionary genommen, vergleich es ruhig mit ner Art config. Und das Dictionary füge ich dynamisch dem Inspektor hinzu. So kann ich verschiedene Gewichtsarten nehmen und deren Werte auch dynamisch setzen.

Darlis schrieb:
Der Inhalt von Settings.Player ist also für die Tonne. Ich glaube fast, diese Zeile sollte da gar nicht stehen, da im weiteren Verlauf immer newBoard.Players nutzt.
In der KI ja, aber wenn ich es nicht schon wegoptimiert habe verwende ich ihn vermutlich im Spielverlauf außerhalb der KI. Bedenke bitte das Spiel besteht nicht nur aus der KI. Der generelle Spielablauf steht ja auch da und der verwendet diese Variable... sagen wir vielleicht, ich weiß nicht ob ich die inzwischen wirklich wegoptimiert hab, wie du vermutest.

Das mit den Dictionaries ist ein guter Hinweis. Ich hab sie tatsächlich sehr inflationell benutzt eben weil ich dachte es ist besser und schöner als Listen (für Laufzeit).
 
Kokujou schrieb:
Ich dachte Dictionaries sind eine gute Lösung weil sie schnellen Zugriff versprechen.
Jein. Für kleine Listen hast du mit klassischem iterieren schneller ein Ergebnis. Dictionaries lohnen erst ab einer gewissen Größe. Programmierer sind faul und Dictionaries sind komfortabel, wenn es dann aber noch schnell sein soll...

Kokujou schrieb:
Ich will die Variablen im Unity-Inspektor verändern können.
Dann macht das natürlich wieder Sinn. Ich habe die Unity-Komponenten ganz außer acht gelassen. Einige Klassen erben auch von Unity-Komponenten. Ein kurzes Googlen gibt aus, diese Komponenten nicht in großem Stil zu erzeugen, die sind irgendwie mit dem Spiel verknüpft. Das müsste mal jemand prüfen, der sich besser mit Unity auskennt.

Kokujou schrieb:
Short oder Byte wäre eine Lösung aber das ist eigentlich völlig egal da die sowieso beim Rechnen in int gecastet werden, wie ich hörte.
Ja, du kannst aber Speicher sparen, wenn die diese als array einsetzt. Als Variable würde ein byte mMn auch wieder 4 Bytes Speicher belegen, so wie ein int.

new Account() schrieb:
Passt doch eher als int: Monate sind 1 - 12, d.h. immer positiv.
Es ist eher ungewöhnlich uint einzusetzen, daher habe ich nachgefragt. Nach deiner Logik müsste hier byte zum Einsatz kommen.
 
Kokujou schrieb:
Ich dachte Dictionaries sind eine gute Lösung weil sie schnellen Zugriff versprechen. Da ich auch mit starken Laufzeitproblemen zu kämpfen habe war das eine Optimierung.
Dictionaries sind nicht zwingend schneller. Wenn du einfach alle Werte iterierst, sind Listen schneller. Wenn du Lookups auf bestimmte Werte brauchst, können Listen schneller sein, wenn die Anzahl der Elemente klein ist.

Bei einer HashTable (das ist ein Dictionary), müssen Werte berechnet (gehasht) werden um zum Element zu gelangen. Das kostet Rechenzeit. Unter anderem hierfür hat jedes Objekt in C# die GetHashCode-Methode.

Kokujou schrieb:
Short oder Byte wäre eine Lösung aber das ist eigentlich völlig egal da die sowieso beim Rechnen in int gecastet werden, wie ich hörte. Und damit wirkt sich das kaum auf die Laufzeit aus
Heute CPUs berechnen dir 64-bit Integers (in C# long) in einer Instruktuion. byte, short etc. sind dann sinnvoll, wenn du millionen an Werten hast und so RAM sparen kannst oder wenn es fachlich schöner ist: "Der Wert einer Farbe eines Pixels kann zwischen 0 und 255 sein".

new Account() schrieb:
Passt doch eher als int: Monate sind 1 - 12, d.h. immer positiv.
Oder noch schöner (wie es glaube ich sogar gelöst ist, wenn ich mich richtig erinnere): ein Enum. Bei integern weiß man sonst nie "war Januar nun 0 oder doch 1?". Ein Paradabeispiel dafür: Das Date Object in JavaScript. Der erste Monat im Jahr ist 0, der erste Tag im Monat ist 1 und der Montag wieder 0 (oder war es doch andersrum? ;))

Nachtrag:
30 Sekunden sind vergangen, seit dem ich mir den Code anschaue und schon finde ich sowas: https://github.com/Kokujou/Hanafuda...ernal/Scripts/KI/Omniscient/Omniscient.cs#L23
So müssen nun in jeder Berechnung mehrere Lookups gemacht werden. Ich weiß nun zwar nicht wie oft die Berechnung ausgeführt wird, aber wenn es (sehr) häufig ist, dann hast du hier auf jeden fall ins negative optimiert. Da deine verfügbaren Weights nicht dynamisch sind, wäre hier eine "[Scope]WeightsConfiguration"-Klasse oder alternative die Variablen direkt in der OmniscientAI Klasse in jeder hinsicht sinnvoller. Du brauchst keine Lookups, du musst nicht mit Strings arbeiten (strings sind verglichen mit Integern und der direkten Nutzung von Variablen sau lahm), und du hast keine Methoden, die nicht das machen, was man von ihnen erwatet (SetWeight("foobar", 123)).

Da du sagst, dass du Performance-Probleme hast: Der sinvollste weg dem hier zu begegnen ist die selbe Antwort wie auch schon beim RAM-Verbrauch: Profiling. Sonst läufst du gefahr, dass du stellen optimierst, die gar kein Problem darstellen (wie es bei meinem Beispiel gerade auch sein kann und wohl auch sein wird).
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: new Account()
Bagbag schrieb:
30 Sekunden sind vergangen, seit dem ich mir den Code anschaue und schon finde ich sowas: https://github.com/Kokujou/Hanafuda...ernal/Scripts/KI/Omniscient/Omniscient.cs#L23
So müssen nun in jeder Berechnung mehrere Lookups gemacht werden. Ich weiß nun zwar nicht wie oft die Berechnung ausgeführt wird, aber wenn es (sehr) häufig ist, dann hast du hier auf jeden fall ins negative optimiert. Da deine verfügbaren Weights nicht dynamisch sind, wäre hier eine "[Scope]WeightsConfiguration"-Klasse oder alternative die Variablen direkt in der OmniscientAI Klasse in jeder hinsicht sinnvoller. Du brauchst keine Lookups, du musst nicht mit Strings arbeiten (strings sind verglichen mit Integern und der direkten Nutzung von Variablen sau lahm), und du hast keine Methoden, die nicht das machen, was man von ihnen erwatet (SetWeight("foobar", 123)).

Wie gesagt das ist eine Unity-Spielerei die nötig war um dynamisch Werte anzeigen zu können. Ich wollte die Variablen Live verändern können während ich meine tausend Testfälle laufen lasse.

Aber ja, ich hab verstanden, Dictionaries lohnen sich bei mir gar nicht und ich kann wieder zurückrädern.

eine int -> byte Optimierung könnte ich eventuell auch noch machen, aber solange mein RAM-Verbrauch nicht nach oben offen ist ist mir die Optimierung relativ egal. Diese Art des Turniers wird ja nur auf meinem Computer angewendet. alles was der Benutzer sieht verbraucht vermutlich nur ein hunderdstel des RAMS. Bestenfalls. Der Spielt ja nicht das ganze Spiel auf knopfdruck 1.000 Mal durch^^

Das Hauptproblem beim RAM war es ja, dass hier plötzlich immer größerer RAM-Verbrauch auftrat ohne dass er auch wieder sank oder eine Grenze fand. Der hätte vermutlich sogar nen Großrechner vollgestopft. aber das ist jetzt irgendwie durch die beschränkung der Parallelität in den Griff gekriegt

Ihr sagted Threads machen nur echt parallele Arbeit. Und Tasks NUR asynchron? Oder machen Tasks beides? das wär echt nützlich zu wissen.

Und Parallel.For nutzt Threads ja? auch das ist eine lehrreiche Information.
 
Kokujou schrieb:
Wie gesagt das ist eine Unity-Spielerei die nötig war um dynamisch Werte anzeigen zu können. Ich wollte die Variablen Live verändern können während ich meine tausend Testfälle laufen lasse.
Oh, das habe ich nicht realisiert, dass ich fast vom selben Rede wie oben. Ich hoffe meine erweiterte Ausführung war trotzdem hilfreich.

Kokujou schrieb:
aber das ist jetzt irgendwie durch die beschränkung der Parallelität in den Griff gekriegt
Das ist aber mehr ein Workaround als eine Lösung.

Kokujou schrieb:
Ihr sagted Threads machen nur echt parallele Arbeit. Und Tasks NUR asynchron? Oder machen Tasks beides? das wär echt nützlich zu wissen.

Und Parallel.For nutzt Threads ja? auch das ist eine lehrreiche Information.
Ja, Threads sind parallel (das sind Threads auf OS-Ebene). Parallel (bzw. der ThreadPool dahinter) nutzt genau diese Threads im Hintergrund. Du kannst das u.A. mit dem Task-Manager beobachten - oder alternativ direkt im Code über Process.GetCurrentProcess().Threads.Count.

Ja, async/await ist innerhalb eines SynchronizationContext asynchron. Tasks nicht unbedingt. Tasks können unter Anderem auch dabei helfen die zwei Welten zu Verbinden. So kannst du mittels Task.Run Arbeit in einem neuen Thread ausführen, auf dessen Ende du in einem asynchronem Kontext mittels await warten kannst.

Task.Run Aufgaben werden übrigens genauso in ein ThreadPool gepackt, wie auch bei Parallel.

Was ich aber noch immer nicht verstanden habe: In wie weit erhoffst du dir hier Besserung durch Asynchronität? Async/await ist eigentlich nur sinnvoll, wenn du externe Ressourcen hast, auf die du warten musst wie bspw. Disk- oder Netzwork-I/O, aber nicht bei CPU-bound Workloads wie du es hier hast.
 
Zuletzt bearbeitet:
Also gibt es bei Threads nur parallel oder synchron. Immer parallel kann nicht sein, wenn ich 2886 Threads im Manager sehe ;) Ich nehme an die werden gequeuet und dann parallel gerechnet... ja ich denke das macht sinn für mich.

Bagbag schrieb:
Was ich aber noch immer nicht verstanden habe: In wie weit erhoffst du dir hier Besserung durch Asynchronität?
Tu ich ja nicht, eher im Gegenteil. Ich will das eben NICHT asynchron gearbeitet wird. was ich brauche ist parallelität. Ich warte ja auf nichts und kann den Unity-Rendering-Prozess auch ausknippsen. Ich brauche volle Rechenpower bei meinen intensiven berechnungen.

Bagbag schrieb:
Das ist aber mehr ein Workaround als eine Lösung.
Es ist eine Lösung. 1. 100% meiner CPU werden benutzt, also hat das keine Auswirkungen darauf.
2. der Speicherverbrauch ist nun bei etwa 4-5GB begrenzt. Bei dem was ich da tue ist das schon ein ordentliches Resultat.

Eigentlich sollte nicht nur nach jedem Spiel sondern sogar nach jeder Runde der Suchbaum weggeschmissen werden, weiß der geier was da nicht funktioniert, aber ich bin mir zu 100% sicher dass da auch nichts unnütz rumliegt. Vielleicht hats was mit Unity zutun, dass der da was aufbewahrt, ich tue es nicht.

Und wenn Parallel.For offenbar mit meinen... Ja intern nutze ich glaube ich tatsächlich Tasks... ins Gehege kommt und meint da asynchronität reinbringen zu müssen, jetzt macht ers nicht mehr.

Intern, also INNERHALB eines Spiels funktioniert der Aufbau des Spielfelds nämlich auch parallel. was ja das einzige ist was den User interessieren wird. Aber da arbeite ich halt nicht mit parallel.for sondern mit Task.Run. Vielleicht hilfts ja was umzusteigen.

Aber wenn mit weggenommener Parallelität das Problem gelöst oder zumindest reduziert wird heißt das im Klartext dass bei der Parallelisierung was kaputt ist ^^
 

Ähnliche Themen

L
Antworten
6
Aufrufe
1.572
L
Zurück
Oben