How to do the most amount of work possible per frame without lagging?


I’m trying to design a coroutine that does a fairly expensive operation on a variable number of objects, continually. I know there typically won’t be enough computational power to complete this operation on every object each frame. So I want to do the operation on SOME of the objects each frame, and cycle through them. I also want to ensure that I update the maximum number of objects each frame without causing a lag. I.e. the couroutine should not take longer than the frame rate.

I’m brainstorming ways to accomplish this. Right now I’m thinking of starting with a relatively low number of objects to update each frame, the next frame I’ll check the frame rate and make sure it is acceptable, if so I’ll increase the number of objects to update, and continue doing this until the frame rate decreases, and go back by one.

Does this sound like a sensible approach or is there a better way to accomplish this? Thanks.

If you don’t need to complete the task per frame, here’s one possible solution:

// C#
float timeStamp; // This will keep track of how long an operation takes.
public float targetFrameRate = 60.0f; // Your intended framerate. Details below script.
float maximumTimePerFrame; // Here, you'll enforce a maximum delay between frames.

void Start()
	maximumTimePerFrame = 1.0f / targetFrameRate;

IEnumerator MyOperation()
	timeStamp = Time.realtimeSinceStartup;
	while(**DOING STUFF**) // i.e. if intended for non-stop calculation, while(true) would even do the trick
		// do stuff here
		if(Time.realtimeSinceStartup > timeStamp + maximumTimePerFrame)
			yield return null(); // wait for next frame of gameplay
			timeStamp = Time.realtimeSinceStartup;

This will give you a fundamental performance monitor to ensure a framerate above a specified threshhold while performing calculations in a virtually endless loop (or endless, depending on implementation). The key element preventing the endless loop from freezing Unity is time monitoring paired with yield in the coroutine.

That said, specifying a framerate manually is probably not a good idea: If performance is already bad for a player, then this offloaded task will function extremely slowly, if there’s any urgency in its completion.

Because of this, it may be prudent to monitor average frame rate and throttle the target frame rate relative to that (ensuring that the target doesn’t continuously drop due to the calculations performed taxing the hardware).

That said, another option, especially for purely aesthetic calculations and tasks, would be multithreading (see this answer by @Bunny83 for a reasonable implementation), but do be aware that Unity and multithreading don’t get along well. If additional threads aren’t properly monitored, you can do wonderful things to your computer.

As an example of an aesthetic task, I’ve created separate thread(s) for processing vertex colors in conjunction with a shader to apply ripples to water surfaces. By putting it in a separate thread, tens of thousands of calculations were saved per frame for something that didn’t have any need to negatively impact performance.

Anyway, to really answer your question, coroutines with time monitoring are a fairly easy solution to implement and will be sufficient in a majority of circumstances. The more important the calculations being performed, the more carefully you’ll want to monitor how many are processed per frame.