是什么使Enum.HasFlag这么慢?

我在进行一些速度测试时,发现Enum.HasFlag比使用按位运算慢大约16倍。

有谁知道Enum.HasFlag的内部原理,为什么它这么慢?我的意思是说慢两倍不会太糟糕,但是当它慢16倍时,它会使该功能不可用。

如果有人想知道,这里是我用来测试其速度的代码。

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

namespace app

{

public class Program

{

[Flags]

public enum Test

{

Flag1 = 1,

Flag2 = 2,

Flag3 = 4,

Flag4 = 8

}

static int num = 0;

static Random rand;

static void Main(string[] args)

{

int seed = (int)DateTime.UtcNow.Ticks;

var st1 = new SpeedTest(delegate

{

Test t = Test.Flag1;

t |= (Test)rand.Next(1, 9);

if (t.HasFlag(Test.Flag4))

num++;

});

var st2 = new SpeedTest(delegate

{

Test t = Test.Flag1;

t |= (Test)rand.Next(1, 9);

if (HasFlag(t , Test.Flag4))

num++;

});

rand = new Random(seed);

st1.Test();

rand = new Random(seed);

st2.Test();

Console.WriteLine("Random to prevent optimizing out things {0}", num);

Console.WriteLine("HasFlag: {0}ms {1}ms {2}ms", st1.Min, st1.Average, st1.Max);

Console.WriteLine("Bitwise: {0}ms {1}ms {2}ms", st2.Min, st2.Average, st2.Max);

Console.ReadLine();

}

static bool HasFlag(Test flags, Test flag)

{

return (flags & flag) != 0;

}

}

[DebuggerDisplay("Average = {Average}")]

class SpeedTest

{

public int Iterations { get; set; }

public int Times { get; set; }

public List<Stopwatch> Watches { get; set; }

public Action Function { get; set; }

public long Min { get { return Watches.Min(s => s.ElapsedMilliseconds); } }

public long Max { get { return Watches.Max(s => s.ElapsedMilliseconds); } }

public double Average { get { return Watches.Average(s => s.ElapsedMilliseconds); } }

public SpeedTest(Action func)

{

Times = 10;

Iterations = 100000;

Function = func;

Watches = new List<Stopwatch>();

}

public void Test()

{

Watches.Clear();

for (int i = 0; i < Times; i++)

{

var sw = Stopwatch.StartNew();

for (int o = 0; o < Iterations; o++)

{

Function();

}

sw.Stop();

Watches.Add(sw);

}

}

}

}

结果:HasFlag:52ms 53.6ms 55ms按位:3ms 3ms 3ms

回答:

有谁知道Enum.HasFlag的内部原理,为什么它这么慢?

实际检查只是简单的签入Enum.HasFlag-这不是问题。话虽如此,它比您自己的位检查要慢…

造成这种速度下降的原因有两个:

首先,Enum.HasFlag进行显式检查,以确保枚举的类型和标志的类型都是相同的类型,并且来自相同的枚举。这张支票有一些费用。

其次,有一个不幸的箱和值的拆箱一次转化的过程中UInt64发生的内部的HasFlag。我认为,这是由于必须Enum.HasFlag与所有枚举一起使用,而与基础存储类型无关。

话虽如此,它有一个巨大的优势Enum.HasFlag-它可靠,整洁,并使代码非常明显和富有表现力。在大多数情况下,我认为这值得付出成本-

但是,如果您在性能非常关键的循环中使用它,则值得自己检查一下。

以上是 是什么使Enum.HasFlag这么慢? 的全部内容, 来源链接: utcz.com/qa/417782.html

回到顶部