Which is the fastest kind of C# function in Unity? There are several to choose from: regular old instance methods, static methods, delegates, and lambdas. Is there any performance reason to choose one over the other? Today’s article answers just these questions by putting each type of function to the test. Read on to see which is fastest and which is slowest!

Just like AS3 functions in Flash, there are several types to choose from. Here are the candidates for C#:

class MyCode
{
	// Instance function
	void InstanceFunction() { }
 
	// Static function
	static void StaticFunction() { }
 
	// Definition of a function - not a function itself
	delegate void FunctionType();
 
	// Delegate function
	FunctionType DelegateFunction = delegate() {};
 
	// Lambda function
	FunctionType Lambda = () => {};
}

The first two are normal, but the latter two are a bit tricky. In order to be called they must be saved to a delegate-typed variable. The standard System.Action and System.Func are common options, but you can define your own like I did above.

Now let’s put each kind of function to the test by calling them a lot of times. Here’s the test script:

using System;
using System.Diagnostics;
 
using UnityEngine;
 
public class TestScript : MonoBehaviour
{
	private const int reps = 100000000;
	private string report;
 
	void Start()
	{
		var stopwatch = new Stopwatch();
 
		var staticFunctionTime = RunTest(
			stopwatch,
			() => {
				for (var i = 0; i < reps; ++i)
				{
					StaticFunction();
				}
			}
		);
 
		var instanceFunctionTime = RunTest(
			stopwatch,
			() => {
				for (var i = 0; i < reps; ++i)
				{
					InstanceFunction();
				}
			}
		);
 
		var lambdaTime = RunTest(
			stopwatch,
			() => {
				Action lambda = () => {};
				for (var i = 0; i < reps; ++i)
				{
					lambda();
				}
			}
		);
 
		var delegateTime = RunTest(
			stopwatch,
			() => {
				Action del = delegate(){};
				for (var i = 0; i < reps; ++i)
				{
					del();
				}
			}
		);
 
		report = "Test,Time\n" +
			"Static Function," + staticFunctionTime + "\n" +
			"Instance Function," + instanceFunctionTime + "\n" +
			"Lambda," + lambdaTime + "\n" +
			"Delegate," + delegateTime + "\n";
	}
 
	private long RunTest(Stopwatch stopwatch, Action test)
	{
		stopwatch.Reset();
		stopwatch.Start();
		test();
		return stopwatch.ElapsedMilliseconds;
	}
 
	void OnGUI()
	{
		GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report);
	}
 
	static void StaticFunction() {}
	void InstanceFunction() {}
}

If you want to try out the test yourself, simply paste the above code into a TestScript.cs file in your Unity project’s Assets directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:

  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.10.2
  • Unity 5.0.0f4, Mac OS X Standalone, x86_64, non-development
  • 640×480, Fastest, Windowed

And got these results:

Test Time
Static Function 34
Instance Function 30
Lambda 278
Delegate 276

Unity Function Performance Graph

The above data shows a distinct division between the first two types of functions and the last two. The instance and static functions run about 10x faster than the lambda and delegate functions. The instance and static functions seem to run at about the same speed, just like the lambda and delegate functions.

These functions don’t do anything, so these results just show the overhead of calling the function, not the time taken by the actual work the function should do.

The test app calls each type of function 100 million times. This shows that each function call, regardless of type, is really quite fast. The “slow” function types have a per-call cost of 0.000003 milliseconds. That means you could call them a third of a million times before you’d used up one millisecond of time in function call overhead. For the “fast” function types, you could call three million times.

So you’ll probably never see any slowdown due to lambdas or delegates, but if you happen to be calling them a lot then you can optimize by switching to instance functions or static functions.

If you know of any other types of functions I missed or have any experience with real-world slowdowns due to function call overhead, feel free to leave a comment!