Skip to content

Instantly share code, notes, and snippets.

@ljw1004
Created April 20, 2017 15:02
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ljw1004/61bc96700d0b03c17cf83dbb51437a69 to your computer and use it in GitHub Desktop.
Save ljw1004/61bc96700d0b03c17cf83dbb51437a69 to your computer and use it in GitHub Desktop.
Perf comparison ValueTuple vs Tuple vs KeyValuePair
// TUPLE MICRO-BENCHMARKS, based on https://www.dotnetperls.com/tuple-keyvaluepair
//
// Tuples are generally fastest.
// ValueTuple is fastest in the particular case of GetHashCode.
// KeyValuePair is always worst.
//
//
// RAW RESULTS
// Numbers in milliseconds (lower is better)
//
// Tuple ValueTuple KeyValuePair
// Allocation: 160 100 110
// Argument: 75 80 80
// Return: 75 210 210
// Load: 160 170 320
// GetHashCode: 820 420 2700
// Equals: 280 470 6800
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
class Program {
static void Main() {
var tuple = Tuple.Create("cat", "dog");
var keyValuePair = new KeyValuePair<string, string>("cat", "dog");
var valueTuple = ("cat", "dog");
var tupleList = new List<Tuple<string, string>> { tuple };
var keyValuePairList = new List<KeyValuePair<string, string>> { keyValuePair };
var valueTupleList = new List<(string, string)> { valueTuple };
Experiment("Allocation", "Tuple", () => { var pair = Tuple.Create("cat", "dog"); });
Experiment("Allocation", "ValueTuple", () => { var pair = ("cat", "dog"); });
Experiment("Allocation", "KeyValuePair", () => { var pair = new KeyValuePair<string, string>("cat", "dog"); });
Experiment("Argument", "Tuple", () => { NOP(tuple); });
Experiment("Argument", "ValueTuple", () => { NOP(valueTuple); });
Experiment("Argument", "KeyValuePair", () => { NOP(keyValuePair); });
Experiment("Return", "Tuple", () => { ID(tuple); });
Experiment("Return", "ValueTuple", () => { ID(valueTuple); });
Experiment("Return", "KeyValuePair", () => { ID(keyValuePair); });
Experiment("Load", "Tuple", () => { Z(tupleList); });
Experiment("Load", "ValueTuple", () => { Z(valueTupleList); });
Experiment("Load", "KeyValuePair", () => { Z(keyValuePairList); });
Experiment("GetHashCode", "Tuple", () => { tuple.GetHashCode(); });
Experiment("GetHashCode", "ValueTuple", () => { valueTuple.GetHashCode(); });
Experiment("GetHashCode", "KeyValuePair", () => { keyValuePair.GetHashCode(); });
Experiment("Equals", "Tuple", () => { tuple.Equals(tuple); });
Experiment("Equals", "ValueTuple", () => { valueTuple.Equals(valueTuple); });
Experiment("Equals", "KeyValuePair", () => { keyValuePair.Equals(keyValuePair); });
}
static void Experiment(string title, string kind, Action lambda) {
lambda();
var s = Stopwatch.StartNew();
for (int i = 0; i< 10000000; i++) lambda();
Console.WriteLine($"{title}: {kind}: {s.Elapsed.TotalMilliseconds}ms");
}
[MethodImpl(MethodImplOptions.NoInlining)] static void NOP<T>(T a) { }
[MethodImpl(MethodImplOptions.NoInlining)] static T ID<T>(T a) => a;
[MethodImpl(MethodImplOptions.NoInlining)] static char Z(List<Tuple<string, string>> list) => list[0].Item1[0];
[MethodImpl(MethodImplOptions.NoInlining)] static char Z(List<KeyValuePair<string, string>> list) => list[0].Key[0];
[MethodImpl(MethodImplOptions.NoInlining)] static char Z(List<(string,string)> list) => list[0].Item1[0];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment