gpt4 book ai didi

c# - 为什么访问静态数组引用比访问非静态数组引用慢

转载 作者:行者123 更新时间:2023-12-03 17:10:53 24 4
gpt4 key购买 nike

看看这个片段:

public class StringToggler
{
static readonly bool[] ToggleableLatinChars = new[]
{
// 256 bools here
};

readonly bool[] LocalToggleableLatinChars = ToggleableLatinChars;

public string Toggle(string s)
{
// blah blah

if (LocalToggleableLatinChars[(byte) ch])
{
// blah blah
}

// blah blah
}

// blah blah
}

在测试中,此代码明显比我直接使用 ToggleableLatinChars 更快(大约 7%)。(在该方法中使用对 ToggleableLatinChars 的本地引用也会更快)。

仅在针对 .NET 4 进行编译时才会注意到此效果。当针对 .NET 3.5 进行编译时,我看到了相反的效果 - 使用静态数组明显更快。 (我的机器是运行 Windows 7 64 位的 Intel i5,正在针对 x86 进行编译)

知道为什么吗?

更新:这是一个完整的代码示例,更类似于 Marc 的测试示例。注意我现在使用静态和局部变量版本(不再是成员变量)。尽管我看到的差异小于我在原始测试代码中看到的差异,但在针对 .NET 4 进行编译时,本地版本总是更快。你可以交换运行顺序,但本地总是对我有利。 (编译 .NET 3.5 不会这样做:它总体上比 .NET 4 快得多,并且静态要么更快,要么相同)

using System;
using System.Diagnostics;
using System.Globalization;

internal class Program
{
const int RepeatCount = 500000;

const string TestString1_Unicode = @"?=3.1415926?!! ?a??!#!%# ÜBERGRößEN!!?????? ??????@!e=2.71828182?#!!$@\^i^/!@$";
const string TestString2_Numbers = @"p=3.14159265358979323846264338327950288419716939937510....!!!!";
const string TestString3_LowerCase = @"nevr un-den-erstimate ze pauer of stoopid piplz in larg grupp!\*^*/";
const string TestString4_UpperCase = @"DUDE, WHY U R HERE?? U SHOULDA BE IN THE MEETING (BLAH-BLAH) $\*o*/$!";

static void Main()
{

RunTestsStaticAccess();
RunTestsLocalAccess();

Console.ReadLine();
}

public static void RunTestsLocalAccess()
{
StringToggler st = new StringToggler();

var watch = Stopwatch.StartNew();
for (int i = 0; i < RepeatCount; i++)
{
st.ToggleCase_LocalAccess(TestString1_Unicode);
st.ToggleCase_LocalAccess(TestString2_Numbers);
st.ToggleCase_LocalAccess(TestString3_LowerCase);
st.ToggleCase_LocalAccess(TestString4_UpperCase);
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", "RunTestsLocalAccess", watch.ElapsedMilliseconds);
}

public static void RunTestsStaticAccess()
{
StringToggler st = new StringToggler();

var watch = Stopwatch.StartNew();
for (int i = 0; i < RepeatCount; i++)
{
st.ToggleCase_StaticAccess(TestString1_Unicode);
st.ToggleCase_StaticAccess(TestString2_Numbers);
st.ToggleCase_StaticAccess(TestString3_LowerCase);
st.ToggleCase_StaticAccess(TestString4_UpperCase);
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", "RunTestsStaticAccess", watch.ElapsedMilliseconds);
}

public class StringToggler
{
static readonly bool[] ToggleableLatinChars = new[]
{
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false,
false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, false,
true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, false
};

readonly TextInfo textInfo;

public StringToggler()
{
textInfo = CultureInfo.CurrentCulture.TextInfo;
}

public StringToggler(CultureInfo cultureInfo)
{
textInfo = cultureInfo.TextInfo;
}

public unsafe string ToggleCase_StaticAccess(string s)
{
s = string.Copy(s);

fixed(char* p = s)
{
for (int i = 0; i < s.Length; i++)
{
char ch = p[i];

if (ch <= 0xff)
{
if (ToggleableLatinChars[(byte) ch])
{
p[i] = (char) (ch ^ 0x20);
}
}
else
{
switch (CharUnicodeInfo.GetUnicodeCategory(ch))
{
case UnicodeCategory.UppercaseLetter:
p[i] = textInfo.ToLower(ch);
break;

case UnicodeCategory.LowercaseLetter:
p[i] = textInfo.ToUpper(ch);
break;
}
}
}
}

return s;
}

public unsafe string ToggleCase_LocalAccess(string s)
{
s = string.Copy(s);

var toggleableLatinChars = ToggleableLatinChars;

fixed(char* p = s)
{
for (int i = 0; i < s.Length; i++)
{
char ch = p[i];

if (ch <= 0xff)
{
if (toggleableLatinChars[(byte) ch])
{
p[i] = (char) (ch ^ 0x20);
}
}
else
{
switch (CharUnicodeInfo.GetUnicodeCategory(ch))
{
case UnicodeCategory.UppercaseLetter:
p[i] = textInfo.ToLower(ch);
break;

case UnicodeCategory.LowercaseLetter:
p[i] = textInfo.ToUpper(ch);
break;
}
}
}
}

return s;
}
}
}

最佳答案

简单地说:事实并非如此。我不相信你的(未提供的)测试:

我的结果:

InstanceField: 6035ms
LocalVariable: 5373ms
StaticFieldStaticInitializer: 5364ms
StaticFieldNoInitializer: 5388ms

这与我期望从额外的 ldarg0 和 ldfld (从实例字段获取值)而不是更简单的 ldsfld (从静态字段获取值)或 ldloc0 (从实例字段获取值)联系在一起。局部变量)。

我的代码:

class Program
{
static void Main()
{
new InstanceField().RunTests();
new LocalVariable().RunTests();
new StaticFieldStaticInitializer().RunTests();
new StaticFieldNoInitializer().RunTests();
Console.ReadLine();
}
class InstanceField
{
public bool[] arr= new bool[1024];
public void RunTests()
{
var watch = Stopwatch.StartNew();
int count = 0;
for (int i = 0; i < 500000; i++)
{
for (int j = 0; j < arr.Length; j++)
{
if (arr[j]) count++;
}
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", GetType().Name, watch.ElapsedMilliseconds);
}
}
class LocalVariable
{
public void RunTests()
{
bool[] arr = new bool[1024];
var watch = Stopwatch.StartNew();
int count = 0;
for (int i = 0; i < 500000; i++)
{
for (int j = 0; j < arr.Length; j++)
{
if (arr[j]) count++;
}
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", GetType().Name, watch.ElapsedMilliseconds);
}
}
class StaticFieldStaticInitializer
{
public static bool[] arr = new bool[1024];
public void RunTests()
{
var watch = Stopwatch.StartNew();
int count = 0;
for (int i = 0; i < 500000; i++)
{
for (int j = 0; j < arr.Length; j++)
{
if (arr[j]) count++;
}
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", GetType().Name, watch.ElapsedMilliseconds);
}
}
class StaticFieldNoInitializer
{
public static bool[] arr;
public void RunTests()
{
arr = new bool[1024];
var watch = Stopwatch.StartNew();
int count = 0;
for (int i = 0; i < 500000; i++)
{
for (int j = 0; j < arr.Length; j++)
{
if (arr[j]) count++;
}
}
watch.Stop();
Console.WriteLine("{0}: {1}ms", GetType().Name, watch.ElapsedMilliseconds);
}
}
}

关于c# - 为什么访问静态数组引用比访问非静态数组引用慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6320896/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com