在程序中我们经常碰到比较2个字符串是否相等,那么他们各自的性能又如何了?个人推崇用字符串的实例方法Equals,
它的性能相对较高。
class Program
{
static void Main(string[] args)
{
string str1 = "abcdef";
string str2 = "abc";
str2 = str2 + "def";
PerFormanceCounter p = new PerFormanceCounter();
p.Reset();
Console.WriteLine(str1 == str2);
p.Stop();
Console.WriteLine(p.ElapsedSeconds);
p.Reset();
Console.WriteLine(string.Equals(str1, str2));
p.Stop();
Console.WriteLine(p.ElapsedSeconds);
/*
*/
p.Reset();
Console.WriteLine(str1.Equals(str2));
p.Stop();
Console.WriteLine(p.ElapsedSeconds);
str2 = string.Intern(str2);
p.Reset();
Console.WriteLine(string.ReferenceEquals(str1, str2));
p.Stop();
Console.WriteLine(p.ElapsedSeconds);
Console.ReadLine();
}
}
public class PerFormanceCounter
{
[DllImport("kernel32.dll")]
extern static short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
extern static short QueryPerformanceFrequency(ref long x);
private long frequency;
private long start, end;
public PerFormanceCounter()
{
QueryPerformanceFrequency(ref frequency);
}
public void Reset() { QueryPerformanceCounter(ref start); }
public void Stop() { QueryPerformanceCounter(ref end); }
public double ElapsedSeconds
{
get
{
return (end - start) * 1.0 / frequency;
}
}
public long Frequency
{
get
{
return frequency;
}
}
}
运行效果如图:
从运行结果来看string.ReferenceEquals -> String的实例方法Equals->String的静态方法Equals->string 的 == 性能依次降低。 注意string.ReferenceEquals是比较的引用类型,在程序第一次 运行它的性能可能比Equals低, 但是怎么都比 “==”性能高。
我们来阅读源码看看为什么:
public static bool operator == (String a, String b) {
return String.Equals(a, b);
}
public static bool Equals(String a, String b) {
if ((Object)a==(Object)b) {
return true;
}
if ((Object)a==null || (Object)b==null) {
return false;
}
return EqualsHelper(a, b);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public bool Equals(String value) {
if (value == null)
{
// exception will be thrown later for null this
if (this != null) return false;
}
return EqualsHelper(this, value);
}
private unsafe static bool EqualsHelper(String strA, String strB)
{
int length = strA.Length;
if (length != strB.Length) return false;
fixed(char* ap = strA) fixed(char* bp = strB)
{
char* a = ap;
char* b = bp;
// unroll the loop
#if AMD64
// for AMD64 bit platform we unroll by 12 and
// check 3 qword at a time. This is less code
// than the 32 bit case and is shorter
// pathlength
while (length >= 12)
{
if (*(long*)a != *(long*)b) break;
if (*(long*)(a+4) != *(long*)(b+4)) break;
if (*(long*)(a+8) != *(long*)(b+8)) break;
a += 12; b += 12; length -= 12;
}
#else
while (length >= 10)
{
if (*(int*)a != *(int*)b) break;
if (*(int*)(a+2) != *(int*)(b+2)) break;
if (*(int*)(a+4) != *(int*)(b+4)) break;
if (*(int*)(a+6) != *(int*)(b+6)) break;
if (*(int*)(a+8) != *(int*)(b+8)) break;
a += 10; b += 10; length -= 10;
}
#endif
// This depends on the fact that the String objects are
// always zero terminated and that the terminating zero is not included
// in the length. For odd string sizes, the last compare will include
// the zero terminator.
while (length > 0)
{
if (*(int*)a != *(int*)b) break;
a += 2; b += 2; length -= 2;
}
return (length <= 0);
}
}
其实看了源码大家不难发现
== 调用的是String.Equals方法,所以性能比String.Equals低。而String.Equals首先检查2个对象引用是否相等,如果相等直接返回,否者在调用EqualsHelper方法。 而string的实例方法是直接调用EqualsHelper方法,所以它的性能最高。