Jump to content
Unity Insider Forum

Coroutine oder Invoke(Repeating)?


Helishcoffe

Recommended Posts

Hey ich habe auch mal wieder ne Frage.

Mich würde mal interessieren, wie ihr Parallele Aufgaben abarbeitet. Soll z.B. jede Sekunde irgendwas geprüft werden: Nutzt ihr Coroutines oder ein simples InvokeRepeating? 

Macht ja im Prinzip das Gleiche aber wo genau ist denn eigentlich der Unterschied? Also klar mit Coroutines kann ich ja aufwendige Aufgaben parallel abarbeiten aber ich sehe auch sehr oft, dass für simple Timingaufgaben wie z.B. jede Sekunde was abfragen oder einen Wert verändern auch Coroutines genutzt werden.

Was sagt ihr?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich denke er macht hinter den Kulissen das Gleiche, d.h. der finale Code ist gleich. Man hat mit Coroutines ggf. noch ein paar Möglichkeiten mehr (siehe yield statement, warten aufs nächste Frame etc.), aber der Code wird dadurch auch unübersichtlicher, daher verwende ich Coroutines in der ausgeschriebenen Form nur, wenn etwas mit Invoke oder InvokeRepeat nicht machbar ist. Ich nutze Coroutinen eher für simples Timing und "zeitliche Events", für echte nebenläufige Aufgaben verwende ich dann eher background threads.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Was @Zer0Cool sagt. Parallele Aufgaben kannst du mit keinem von beidem angehen. Die eignen sich nur, um Aufgaben aufzuteilen und dann die kleineren Teile der eigentlichen Aufgabe nacheinander auszuführen. Wenn einer dieser Aufgabenteile dann trotz allem eine Sekunde braucht, dann bleibt das gesamte Spiel eine Sekunde lang stehen. Weil Coroutinen und Invokes eben wie alles andere auch im Main Thread abgearbeitet werden.

Ansonsten... Invoke benutzt halt strings, und mein Hass auf strings ist nach wie vor groß :)

Wenn du richtige Nebenläufigkeit haben willst, dann brauchst du, wie ebenfalls bereits gesagt, Threads. Die lassen sich wiederum prima mit Coroutinen kombinieren. Hab dafür mal diese Klasse geschrieben. Die Benutzung ist sehr einfach:

private void Start()
{
  StartCoroutine(DoSomething());
}

private IEnumerator DoSomething()
{
  yield return new CoroutineThread(() => Thread.Sleep(1000));
  
  print("The thread has finished sleeping.");
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 3 Stunden schrieb Sascha:

Parallele Aufgaben kannst du mit keinem von beidem angehen. Die eignen sich nur, um Aufgaben aufzuteilen und dann die kleineren Teile der eigentlichen Aufgabe nacheinander auszuführen

Ja das meinte ich in diesem Fall mit parallelisieren. Mir gings auch nur darum, welche Methode halt intern besser zu benutzen ist wenn es um kleine Aufgaben geht, die man timen möchte. Bzw. ob ein Performanceunterschied besteht und wie groß dieser ist

Link zu diesem Kommentar
Auf anderen Seiten teilen

Von einem Performanceunterschied würde ich nicht ausgehen. Vor allem nicht, wenn du nicht vorhast, ein paar Tausend solcher Timer gleichzeitig zu haben. Aber vielleicht hat da ja jemand mal nen Benchmark für gemacht.

Besser zu benutzen... Gechmackssache. Ich sag ja, strings sind die Pest und Invoke(Repeating) geht nicht ohne. Dafür haste da nen One-Liner mit. Ich überlege aber gerade... da sollte sich kurz ne CustomYieldInstruction schreiben lassen, die das augleicht.

Bin gleich wieder da.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 3 Minuten schrieb Helishcoffe:

Ja das meinte ich in diesem Fall mit parallelisieren. Mir gings auch nur darum, welche Methode halt intern besser zu benutzen ist wenn es um kleine Aufgaben geht, die man timen möchte. Bzw. ob ein Performanceunterschied besteht und wie groß dieser ist

Ich vermute es gibt keinen Performanceunterschied.

Link zu diesem Kommentar
Auf anderen Seiten teilen

So... fertig.

CustomYieldInstruction ist Quatsch, einfach ne neue Coroutine schreiben. Hier hast du ne Klasse:

using System;
using System.Collections;
using UnityEngine;

public static class Invoker
{
    public static IEnumerator InvokeRepeating(Action action, float initialDelay, float delay)
    {
        if(initialDelay < 0 || delay < 0) yield break;

        var countdown = initialDelay;

        while(true)
        {
            countdown -= Time.deltaTime;
            while(countdown <= 0)
            {
                countdown += delay;
                action();
            }
            yield return null;
        }
    }
}

Benutzt wird sie so:

StartCoroutine(Invoker.InvokeRepeating(MeineMethode, 2f, 3f));
// oder ohne ne fest definierte Methode
StartCoroutine(Invoker.InvokeRepeating(() => Debug.Log("Hallo!"), 2f, 3f));

Also fast genauso wie MonoBehaviour.InvokeRepeating, nur ohne den doofen string.

Wenn du das Ding abbrechen willst, merk dir die zurückgegebene Coroutine:

private Coroutine stuffDoer;

private void Start()
{
  stuffDoer = StartCoroutine(Invoker.InvokeRepeating(MeineMethode, 2f, 3f));
}

public void StopDoingStuff()
{
  StopCoroutine(stuffDoer);
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...