型の判別その2

 ジェネリックもちょっと交えて調べてみる。

Static 200 181 178
Generic 393 358 379
IsInstanceOf 628 582 633
Equal 254 239 258
GenericEqual 256 238 256

 昨日言ったことと矛盾するけどただのis演算子が一番速い。オブジェクトの構成を簡単にしたためだろうか。

 対して、is Tの形だとだいぶ遅くなる。ジェネリック型に対するisは多少遅くなる。

 Typeの==は安定している。Genericに対するものも結果は変わらない。しかしループの中で毎回typeof(T)をするようにすると格段に遅くなる。

GenericEqual(typeof(T)) 406 379 407

 といっても1000万回やって0.4秒ぐらいなのでどうということもないだろう。

 IsInstanceOfも結構速い。継承階層の構成次第で早くも遅くもなるようだ。

 結局isと==はどっちが速いのか。昨日のやつを継承階層を単純に、Parentから直接Child12個を派生させる形にして調べてみた。

IsTest 134
EqualTest 103

 まだ==が速い。多分何回もifをやるときに、==だと一度GetType()して取得したTypeを使いまわせるけど、if(item is Type)の形だと暗黙にitem.GetType()を毎回しなきゃならなくなる、といった違いなんじゃなかろうか。わからん。

ソースと結果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;

namespace Test
{
	class R { public int Yes; public int No; }

	class Parent { }
	class Child1 : Parent { }
	class Child2 : Parent { }

	class Program
	{
		
		Parent[] Generate()
		{
			var rand = new Random();

			var module = typeof(Parent).Module;

			return Enumerable.Range(0, 10000000)
				.Select(i =>{
					if (rand.Next(2) == 0)
					{
						return (Parent)new Child1();
					}
					else
					{
						return (Parent)new Child2();
					}

				}).ToArray();
		}


		R Static(Parent[] parents)
		{
			int yes = 0, no = 0;
			for (int i = 0; i < parents.Length; ++i)
			{
				if (parents[i] is Child1)
				{
					++yes;
				}
				else
				{
					++no;
				}
			}
			return new R { Yes = yes, No = no };
		}

		R IsInstanceOf(Parent[] parents)
		{
			int yes = 0, no = 0;
			for (int i = 0; i < parents.Length; ++i)
			{
				if (typeof(Child1).IsInstanceOfType(parents[i]))
				{
					++yes;
				}
				else
				{
					++no;
				}
			}
			return new R { Yes = yes, No = no };
		}

		R Generic<T>(Parent[] parents)
		{
			int yes = 0, no = 0;
			for (int i = 0; i < parents.Length; ++i)
			{
				if (parents[i] is T)
				{
					++yes;
				}
				else
				{
					++no;
				}
			}
			return new R { Yes = yes, No = no };
		}

		R Equal(Parent[] parents)
		{
			int yes = 0, no = 0;
			Type t = typeof(Child1);
			for (int i = 0; i < parents.Length; ++i)
			{
				if (parents[i].GetType() == t)
				{
					++yes;
				}
				else
				{
					++no;
				}
			}
			return new R { Yes = yes, No = no };
		}

		R GenericEqual<T>(Parent[] parents)
		{
			int yes = 0, no = 0;
			Type t = typeof(T);
			for (int i = 0; i < parents.Length; ++i)
			{
				if (parents[i].GetType() == t)
				{
					++yes;
				}
				else
				{
					++no;
				}
			}
			return new R { Yes = yes, No = no };
		}


		void Do(Parent[] parents)
		{
			Stopwatch sw = new Stopwatch();

			sw.Start();
			var s = Static(parents);
			sw.Stop();
			Console.WriteLine("Static " + Tick(sw));

			sw.Reset();
			sw.Start();
			var g = Generic<Child1>(parents);
			sw.Stop();
			Console.WriteLine("Generic " + Tick(sw));

			sw.Reset();
			sw.Start();
			var a = IsInstanceOf(parents);
			sw.Stop();
			Console.WriteLine("IsInstanceOf " + Tick(sw));

			sw.Reset();
			sw.Start();
			var e = Equal(parents);
			sw.Stop();
			Console.WriteLine("Equal " + Tick(sw));

			sw.Reset();
			sw.Start();
			var ge = GenericEqual<Child1>(parents);
			sw.Stop();
			Console.WriteLine("GenericEqual " + Tick(sw));
		}

		long Tick(Stopwatch sw)
		{
			return sw.ElapsedMilliseconds;
		}

		static void Main()
		{
			var p = new Program();
			var sw = new Stopwatch();

			sw.Start();
			var parents = p.Generate();
			sw.Stop();

			Console.WriteLine("Generate " + p.Tick(sw));

			p.Do(parents);
			p.Do(parents);
			p.Do(parents);
		}
	}
}