Jump to content
Unity Insider Forum

Coroutinen


Driller

Recommended Posts

Hey, liebe Community

 

Ich hab da eine Frage zu IEnumeratoren in C#.

Ist es möglich, dass eine Coroutine von zwei Objekten zeitgleich aufgerufen wird und trotzdem richtig funktioniert? Ich hab eine statische Coroutine, welche den Pfad mittels A*-Algorythmus berechnet. Sprich jedes Objekt kann (theoretisch) auf diese statische Coroutine zugreifen und einen Pfad von A ncah B berechnen. Das Ergebnis (also den Pfad) holt sich das aufrufende Objekt/Script dann von einer statischen Variable, welche auf dem selben Script liegt, wie die statische Coroutine. Momentan habe ich das Problem, dass es möglicherweise zu einer Art Interferenz kommt, sobald zwei Objekte zeitgleich einen Pfad berechnen wollen.

 

Ich danke für jede Hilfe,

-Driller

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja da könnte es zu Problemen kommen, weil die Variable ja bei 2 Aufrufen auch 2Mal beschrieben wird.

Setz doch einfach zusätzlich eine Variable, die allen Scripts sagt, dass die Coroutine und das Ergebnis von einem Script belegt ist.

Das Script, was die Berechnung angefordert hat, setzt dann auch diese Variable wieder zurück wenn der Wert ausgelesen wurde.

Danach kann ein anderes Script die Coroutine starten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tja bei mehreren Sekunden Dauer bis zum Ergebnis ist das natürlich nichts.

Die Frage ist jetzt natürlich, warum das so lange dauert und ob bei mehrfachen Starts der Coroutine nicht auch andere Dinge ständig überschrieben würden. Wie z.B. deine Rasterpunkte die ja ihre Wegkosten und Nachbarn ablegen.

Sollte da nichts passieren, dann kannst du auch ein Array an Ergebnisvariablen nutzen, wo natürlich der Coroutine gesagt werden muss, in welche Stelle des Arrays das Ergebnis geschrieben würde.

Dein Aufrufscript weiß dann ja, welche Stelle abgefragt werden muss, weil es ja vorher gesagt hat, welche Stelle beschrieben werden soll.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ist es nicht irgendwie möglich einer Coroutine eine (Ergebnis-)Variable mitzugeben (in Richtung ref-Attribut (Ich weiß, dass grade der in Coroutinen nicht funktioniert)), sodass die Coroutine den Pfad in die gewünschte Variable im Script des aufrufenden Objekts speichert?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich bin etwas verwundert... woher kommt die Idee, man könne nicht einfach zwei Coroutinen gleichzeitig ausführen?

Zwei Coroutinen benutzen weder denselben Speicher (es sei denn, du sagst ihnen explizit, sie sollen es tun), noch sind sie Threads. Es gibt also keine Race Conditions oder so.

 

Dann muss ich nach "statische Coroutine" fragen - so etwas gibt es nämlich schlicht nicht. StartCoroutine ist eine nicht-statische Methode und kann nicht aus einem statischen Kontext aufgerufen werden. Die einzige Möglichkeit, statisch eine Coroutine zu starten ist, ein GameObject zu nehmen (oder zu erstellen) und dieses die Coroutine (nicht-statisch) ausführen zu lassen. Was also meinst du damit?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die einzige Möglichkeit, statisch eine Coroutine zu starten ist, ein GameObject zu nehmen (oder zu erstellen) und dieses die Coroutine (nicht-statisch) ausführen zu lassen.

 

So hab ich es verstanden, denn das Ergebnis wird ja auch in einer static Variable abgelegt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also ich habe eine static class Pathfinding, welche mir mit langen Berechnungen einen Pfad berechnet.

Der Algorythmus in dieser class nennt sich "StartAlgorythm", weshalb der Aufruf folgendermaßen lautet:

 

StartCoroutine (Pathfinding.StartAlgorythm);

 

Die Routine selbst ist static, in der static class Pathfinding. Jedoch wird sie von nicht statischen Klassen aufgerufen.

Diese aufrufenden Klassen können alles mögliche sein, was einen Pfad berechnen will. Ein Mensch das irgendwohin gehen will, ein Tier, etc.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ah, verstehe. Dein Code sieht aber doch etwas komisch aus, denn eigentlich wird StartCoroutine der IEnumerator übergeben, den die Methode zurück gibt; nicht die Methode selbst.

Es müsste also heißen:

StartCoroutine(Pathfinding.StartAlgorithm());

Man bemerke die Klammern.

 

Vielleicht erübrigt sich dann auch deine Frage. Eine Methode kann man immer und überall aufrufen und jedes Mal, wenn man StartAlgorithm aufruft, kommt ein neuer IEnumerator zurück.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, genau so wie du mehrmals gleichzeitig eine Funktion aufrufen kannst, kannst du auch mehrmals eine Coroutine starten und es spielt in diesem Fall auch keine Rolle ob es statisch oder nicht ist. Hier ist selbst der Gedanke an "gleichzeitig" falsch. Nichts kann in deinem Code gleichzeitig passieren, weil das eigentlich in einem Thread passiert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn du eine Funktion hast:

public static float add(float a, float 
{
 return a + b;
}

...dann kann die von zwei anderen Objekten aufgerufen werden. Damit erzähle ich hier nichts neues.

Aber der Witz ist, dass eine Coroutine nicht anders ist.

public static IEnumerator DoNextFrame()
{
 yield return null;
 DoSomething();
}

Es gibt einfach keinen Grund, warum diese Funktion nicht zwei Mal aufgerufen werden können sollte, auch wenn ein anderer Aufruf dieser Funktion irgendwo noch läuft.

 

Übrigens würde ich empfehlen, wirklich aufwändige Berechnungen in einen oder mehrere Threads auszulagern, denn in einer Coroutine verbrauchen sie immer noch Zeit des Main Threads.

Link zu diesem Kommentar
Auf anderen Seiten teilen

So ich habe jetzt meine Antworten gelöscht, weil diese zu keinem Ergebnis führen würden, nach dem der Author sucht ;)

 

Oh, das würde ich nicht sagen. Unity-Coroutinen und Threads sind wie Bonnie und Clyde. Siehe z.B. hier.

 

Jop. habe mir das angeschaut. Macht natürlich Sinn die Coroutine dann in einen anderen Thread zu verlagern. Damit wird der MainThread frei und kann weitere Funktionen ausführen. Da du dich hier wohl besser auskennst, kannst du hier vielleicht schreiben wie das mit mainThread und Prozessor-Kernen ist? So wie ich verstanden habe benutzt ein Thread immer einen Kern, ist das auch bei mainThread so? Was ist wenn der mainThread überladen ist, wird dann trotzdem immer noch ein Kern benutzt und die anderen x Kerne schauen da nur zu?

 

Ich hatte nur nicht daran gedacht den yield method als erstes in den IEnumerator zu bringen, sondern hatte es so verstanden, dass man in der coroutine immer wieder yield return null aufrufen möchte bis das Ergebnis irgendwann fertig ist, dann würde man ja immer wieder ein frame warten und das würde die Dauer in die Unendlichkeit treiben. Aber so wie du es oben geschrieben hast mit einmal yield und dann alles andere läufst sehr gut ;) Wieder was dazugelernt :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Was ist wenn der mainThread überladen ist, wird dann trotzdem immer noch ein Kern benutzt und die anderen x Kerne schauen da nur zu?

 

Der mainThread kann nicht "überladen" sein.

Es kann länger dauern einen Cycle durchzulaufen, als du es dir wünschen würdest (die FPS droppen) aber das juckt ja weder das Betriebssystem, noch die Runtime Environment oder sonst irgendwas ^^

Vorallem könnte und soll das System ja nicht einfach Teile des Codes auf die Kerne auslagern. Multithreading und Multi-Core-Computing birgt eine Meeenge Fallstricke, da gibt es teilweise ganze Frameworks und sogar Programmiersprachen die einfach darauf optimiert sind den Code (möglichst automatisiert) auf verschiedene Kerne oder Rechner zu verteilen.

 

Wenn du einen Thread starten willst müsstest du die Werkzeuge des .NET Frameworks benutzen. Ich würde da eigentlich immer einen ThreadPool benutzen. Dann minimierst du Seiteneffekte wie Thrashing und kannst das System wohl am effizientesten Ausnutzen (je nach dem wie du deinen Code natürlich schreibst ^^)

Allerdings darfst du in Threads keine Unity API benutzen, da die nicht Threadsafe ist und dann mit Errors rumwirft.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...