# Possible to yield a coroutine when it is taking too long to run?

Suppose I have a function that raycasts from (0,0,0) to every object in the scene. Sometimes the scene contains just a couple objects and sometimes it contains several hundred. Is it possible to setup the raycasting function in a way that ensures a good framerate? For example, within the "for" loop that shoots the rays could I somehow evaluate how much time has passed since the loop started and "yield return null" if the time in seconds is greater than the target time of each frame?

You can use Time.realtimeSinceStartup as reference for the time passed:

IEnumerator Test() {
float startTime = Time.realtimeSinceStartup;

foreach( Raycast rc in RaycastArray) {
if( Time.realtimeSinceStartup - startTime < 0.01f ) { //Process stuff for 10 miliseconds
//PROCESS A RAYCAST
}
else {
yield return null;
//Its important that the new time is assigned AFTER the yield
startTime = Time.realtimeSinceStartup;
}
}
}

• this is exactly what I needed. Do you know if this kind of thing is a common/standard practice for optimization? – GeoJohn Sep 22 '16 at 16:16
• Not that I know of. You could probably improve it by dynamically change the time the couroutine spends on each cycle. Like monitor the average deltaTime and never spend enough time to increase the deltaTime above certain threshold. You could even process information every X cycles. I bet there is a lot to it in order to improve performance under several scenarios. – Leo Sep 22 '16 at 16:53
• I'd say that time slicing tasks like this is pretty common. Not necessarily in this implementation, but in one way or another it is done. – Draco18s Oct 23 '18 at 2:58

This is my version of Leo's answer. Pretty handy tool for splitting up the workload of certain loops to help with FPS. Bit hard to predict how long each loop will take though, but probably something I'll work on further.

IEnumerator ForOverTime (int fpsLimit, float timeLimit)
{
float processStartTime = Time.realtimeSinceStartup;
float frameStartTime = processStartTime;
fpsLimit = System.Math.Max(0, fpsLimit);
fpsLimit = fpsLimit == 0 ? 1 : fpsLimit;
timeLimit = System.Math.Max(0f, timeLimit);

for (int i = 0; i < 10000; i++)
{
if (Time.realtimeSinceStartup - frameStartTime < 1f / (float)fpsLimit ||  (timeLimit > 0f && Time.realtimeSinceStartup - processStartTime > timeLimit))
{
print("Do Something. " + Time.frameCount);
}
else
{
yield return null;
frameStartTime = Time.realtimeSinceStartup;
}
}
print("Time taken: " + (Time.realtimeSinceStartup - processStartTime));
}