Return value from coroutine to non monobehaviour


I have a class which is not a monobehaviour (lets call it “Generation”), and as such running CoRoutines from within are not an option.

I have a monobehaviour (lets call this “TestScript”) which needs to call a function within Generation. One parameter required is a Func>. It then calls that Func multiple times, expecting a result in the form of a double. The problem, is that it takes time to return, it needs to run across many frames, and so it kicks off some Coroutines (as this is in the monobehaviour). I set it to return a Task so that I could use Threading.SpinWait.SpinUntil and only return after the coroutines have exited, but this just hangs the main Unity thread.

Here is the function I am calling:

        public void AssessGeneration(Func<NeuralNet, Task<double>> assessment)
            foreach (NeuralNet neuralNet in neuralNets)
                neuralNet.Fitness = assessment(neuralNet).Result;
                neuralNet.fitnessAssessed = true;

So, I’ve tried many other things, such as moving the SpinWait into the Generation class, but still hangs. I’ve tried calling the function in Generation within a Task on a new thread, but when it attempts to run the coroutines it complains about not being on the main thread.

So - I have a function, in a class not inheriting from MonoBehaviour. It is called from a MonoBehaviour, and must pass in a function which takes a parameter of type NeuralNet, and returns a double. It must return a double after a coroutine has finished, but I can’t be blocking the main thread.

If you call SpinWait you basically remove all advantages of using threads as you will make the tread that calls SpinWait to wait at the point until the thread / task is completed. You may want to check the IsCompleted property of the Task class inside a coroutine like this:

while (!task.IsCompleted)
    yield return null;

This will keep the coroutine running while checking every frame if your task is completed.

Keep in mind that Unity’s scripting environment runs on a single thread only, the main thread. This includes coroutines. Also keep in mind that coroutines are not normal “methods” but generator methods. They return an instance of a statemachine object. This statemachine actually represents the body of your coroutine. This statemachine, one passed to StartCoroutine, is driven by Unity’s coroutine scheduler on the main thread. So when you block any piece of code inside a coroutine the whole main thread will block. Coroutines are not threads. They implement cooperative multitasking. If you do not cooperate the whole application breaks ^^. When you do a yield return you basically give the control back to Unity.