Using a Coroutine to Distribute Loop Processing Over Several Frames?

Hi folks, I’m trying to figure out how to spread loops over large sets over time so they don’t suck up too many fps. Here’s what I’ve come up with.

Is there a known better way or any other comments on how to approach this problem?

Anyone have a better way to handle pauses? Perhaps allow completion of the coroutin on pause and then restart on unpause? The current method works and when paused I see a huge increase in FPS, which is good.

IEnumerator LoadBalancedLoop() {
	float breakTime;
	int i = 0;
	int length = 2000000; //would be Array.Length-1;
	float maxTimePerStep = 1/1200f;
	while (true) {
		//isSimPaused is my own pause bool, means calculations not needed
		while (!isSimPaused  Time.realtimeSinceStartup < breakTime) {
			if (i % 100000 == 0) {
				//Debug.Log is slow enough to alter results, so turn off except for debugging
				Debug.Log(i+" indexed at RealTime:"+Time.realtimeSinceStartup);
			}				
			i++;
			if (i > length) {
				//reached end of array. Reset and get out
				//or could start over and not break
				i = 0;
				break;
			}
			//would operate on array[i] here
		}
		yield return null;
	}
	yield return null;		
}

It’s better just to use threads.

–Eric

Oh, that would be nice. I thought unity was not thread-able though. I should mention I am using things like Raycast inside the loop.

Yeah, Raycast wouldn’t work since the Unity API is not thread-safe. You can use any thread-safe Mono functions in threads though.

–Eric

As I thought, thanks. It’s possible I could get rid of the Raycasting dependency in this case, but meanwhile…

I just tried implementing my concept in a fairly complex loop (testing Line-of-sight for each and every Entity in the scene). This has loops inside loops and is hard to deconstruct as I had it above. I came up with a less pretty but easier to use method.
Again, anyone run into trouble doing it this way?

public IEnumerator LoadBalancedUpdateView ()
{

	float maxTimePerStep = 1 / 1200f;
	float breakTime = Time.realtimeSinceStartup + maxTimePerStep;
	bool didYield = false;
		
	while (true) {
		if (LevelManager.isSimPaused) {
			yield return new WaitForSeconds(1);
		}
		if (LevelManager.isSimPaused) {
			// this looks weird but takes advantage of the fact that the
 			// loop picks up here after the yield, so we 'do not pass go' and
			// go back to top and check against isSimPaused				
			continue;
		}
                //some loops within loops here and at a likely spot I put in this.
                //in fact I think these could be sprinkled through the loops just after likely bottle-necks
  		foreach (thing in these) {
                   foreach(foo in bar) { 
			if (Time.realtimeSinceStartup > breakTime) {
				didYield = true;
				yield return null;
			}

			if (didYield) {
				//picking up again after a yield 
				//reset the time we should return from;
				breakTime = Time.realtimeSinceStartup + maxTimePerStep;
				didYield = false;
			}