メソッドの引数の違いでのパフォーマンス計測をして見始めました。
rksoftware.hatenablog.com
計測には BenchmarkDotNet ( NuGet Gallery | BenchmarkDotNet 0.13.11 ) を使用してみました。
今回は、メソッドの定義上の引数の型でなく、実際に引数に渡す変数の実際の型でどうなるか見てみます。
検証コード 1
namespace ClassLibrary1 { public static class MethodExtensions { public static int ExtensionMethod(this object s) => 0; public static int ExtensionMethodInt(this int s) => 0; public static int ExtensionMethodString(this string s) => 0; } }
using ClassLibrary1; BenchmarkDotNet.Running.BenchmarkRunner.Run<Sample>(new BenchmarkDotNet.Configs.DebugInProcessConfig()); public class Sample { int[] ints = new int[short.MaxValue]; object o = new object(); object o_i = 1; object o_s = ""; int i = 0; string s = ""; [BenchmarkDotNet.Attributes.Benchmark] public void MethodObject() { foreach (var c in ints) o.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodObjectInt() { foreach (var c in ints) o_i.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodIntObject() { foreach (var c in ints) ((object)i).ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodObjectString() { foreach (var c in ints) o_s.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodStringObject() { foreach (var c in ints) ((object)s).ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodInt() { foreach (var c in ints) i.ExtensionMethodInt(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodString() { foreach (var c in ints) s.ExtensionMethodString(); } }
実行
1 回目
Method | Mean | Error | StdDev |
---|---|---|---|
MethodObject | 12.46 us | 0.274 us | 0.737 us |
MethodObjectInt | 11.40 us | 0.225 us | 0.490 us |
MethodIntObject | 11.16 us | 0.206 us | 0.183 us |
MethodObjectString | 11.10 us | 0.216 us | 0.202 us |
MethodStringObject | 11.00 us | 0.177 us | 0.157 us |
MethodInt | 11.29 us | 0.218 us | 0.469 us |
MethodString | 11.14 us | 0.223 us | 0.305 us |
2 回目
Method | Mean | Error | StdDev | Median |
---|---|---|---|---|
MethodObject | 11.98 us | 0.239 us | 0.276 us | 11.98 us |
MethodObjectInt | 11.34 us | 0.226 us | 0.501 us | 11.16 us |
MethodIntObject | 11.14 us | 0.210 us | 0.295 us | 11.08 us |
MethodObjectString | 10.90 us | 0.213 us | 0.178 us | 10.86 us |
MethodStringObject | 10.95 us | 0.216 us | 0.337 us | 10.90 us |
MethodInt | 10.94 us | 0.207 us | 0.358 us | 10.83 us |
MethodString | 13.21 us | 0.728 us | 2.112 us | 13.03 us |
3 回目
Method | Mean | Error | StdDev | Median |
---|---|---|---|---|
MethodObject | 11.79 us | 0.225 us | 0.292 us | 11.71 us |
MethodObjectInt | 11.09 us | 0.213 us | 0.167 us | 11.09 us |
MethodIntObject | 11.25 us | 0.222 us | 0.515 us | 11.05 us |
MethodObjectString | 11.15 us | 0.223 us | 0.575 us | 10.90 us |
MethodStringObject | 10.85 us | 0.143 us | 0.140 us | 10.85 us |
MethodInt | 11.02 us | 0.219 us | 0.300 us | 10.96 us |
MethodString | 11.06 us | 0.216 us | 0.337 us | 10.94 us |
4 回目
Method | Mean | Error | StdDev |
---|---|---|---|
MethodObject | 11.90 us | 0.232 us | 0.348 us |
MethodObjectInt | 11.43 us | 0.226 us | 0.481 us |
MethodIntObject | 11.03 us | 0.161 us | 0.143 us |
MethodObjectString | 11.19 us | 0.220 us | 0.379 us |
MethodStringObject | 11.08 us | 0.215 us | 0.211 us |
MethodInt | 11.16 us | 0.218 us | 0.327 us |
MethodString | 11.06 us | 0.216 us | 0.231 us |
■ 結果
ほとんど変わりませんね。けれど、object 型のオブジェクトの場合が遅いということは言えそうです。
あと気持ち程度、int や string のメソッドが少し早い気もしますが気のせいかもしれないレベルですね。
検証コード 2
object 型の変数を ToString() で文字列にしてメソッド呼び出ししてみます。
namespace ClassLibrary1 { public static class MethodExtensions { public static int ExtensionMethod(this object s) => 0; } }
using ClassLibrary1; BenchmarkDotNet.Running.BenchmarkRunner.Run<Sample>(new BenchmarkDotNet.Configs.DebugInProcessConfig()); public class Sample { int[] ints = new int[short.MaxValue]; object o = new object(); object o_s = ""; [BenchmarkDotNet.Attributes.Benchmark] public void MethodObject() { foreach (var c in ints) o.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodObjectToString() { foreach (var c in ints) o.ToString()!.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodObjectString() { foreach (var c in ints) o_s.ExtensionMethod(); } [BenchmarkDotNet.Attributes.Benchmark] public void MethodObjectStringToString() { foreach (var c in ints) o_s.ToString()!.ExtensionMethod(); } }
実行
1 回目
Method | Mean | Error | StdDev |
---|---|---|---|
MethodObject | 11.93 us | 0.238 us | 0.551 us |
MethodObjectToString | 334.09 us | 6.545 us | 8.737 us |
MethodObjectString | 10.62 us | 0.205 us | 0.219 us |
MethodObjectStringToString | 10.54 us | 0.184 us | 0.172 us |
2 回目
Method | Mean | Error | StdDev |
---|---|---|---|
MethodObject | 12.15 us | 0.242 us | 0.391 us |
MethodObjectToString | 325.80 us | 6.365 us | 10.809 us |
MethodObjectString | 11.33 us | 0.223 us | 0.298 us |
MethodObjectStringToString | 11.37 us | 0.223 us | 0.305 us |
結果
やはり object 型のオブジェクトが遅いようですね。他は誤差のレベル、というか実行ごとに前後するレベルです。
まとめ
誤差レベルですが、やはり int や string を直接引数の型にできるならそうしておいた方が無難そうです。ただ最強は ref 値型なのだと思うのでまた後日動かしてみたいです。