Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NETFramework中进行字符串实习-有什么好处以及何时使用实习_C#_.net_String_Performance_String Interning - Fatal编程技术网

C# 在.NETFramework中进行字符串实习-有什么好处以及何时使用实习

C# 在.NETFramework中进行字符串实习-有什么好处以及何时使用实习,c#,.net,string,performance,string-interning,C#,.net,String,Performance,String Interning,我想知道针对.Net framework的字符串实习的过程和内部结构。我还想知道使用实习的好处,以及我们应该使用字符串实习来提高绩效的场景/情况。虽然我从杰弗里·里克特的CLR书中学习过实习,但我仍然感到困惑,希望了解更多细节 [编辑]使用以下示例代码询问特定问题: private void MethodA() { string s = "String"; // line 1 - interned literal as explained in the answer

我想知道针对.Net framework的字符串实习的过程和内部结构。我还想知道使用实习的好处,以及我们应该使用字符串实习来提高绩效的场景/情况。虽然我从杰弗里·里克特的CLR书中学习过实习,但我仍然感到困惑,希望了解更多细节

[编辑]使用以下示例代码询问特定问题:

private void MethodA()
{
    string s = "String"; // line 1 - interned literal as explained in the answer        

    //s.intern(); // line 2 - what would happen in line 3 if we uncomment this line, will it make any difference?
}

private bool MethodB(string compareThis)
{
    if (compareThis == "String") // line 3 - will this line use interning (with and without uncommenting line 2 above)?
    {
        return true;
    }
    return false;
}

实习是一个内部实施细节。与拳击不同,我不认为知道的比你在里希特的书中读到的更多有什么好处

手动插入管柱的微观优化效益最小,因此通常不建议使用

这可能描述了它:

class Program
{
    const string SomeString = "Some String"; // gets interned

    static void Main(string[] args)
    {
        var s1 = SomeString; // use interned string
        var s2 = SomeString; // use interned string
        var s = "String";
        var s3 = "Some " + s; // no interning 

        Console.WriteLine(s1 == s2); // uses interning comparison
        Console.WriteLine(s1 == s3); // do NOT use interning comparison
    }
}

通常,当您使用文字字符串值时,实习是自动发生的。Interning提供了在内存中只保留一个文本副本的好处,无论使用频率如何

也就是说,很少有理由对自己在运行时生成的字符串进行内部调用,或者甚至考虑过为正常开发进行字符串内部调用

如果您要对可能相同的运行时生成的字符串进行大量比较,那么可能会有一些好处(因为实习可以通过ReferenceEquals加速比较)。然而,这是一个高度专业化的用法,需要大量的分析和测试,除非有一个被测量的问题,否则不会是一个优化。

< P>这是一个“老”的问题,但我有不同的角度。 如果要从一个小的池中获得大量长寿命字符串,那么实习可以提高内存效率

在我的例子中,我在一个静态字典中实习了另一种类型的对象,因为它们经常被重用,这在将它们持久化到磁盘之前充当了一个快速缓存

这些对象中的大多数字段都是字符串,值池相当小(无论如何,要比实例的数量小得多)

如果这些是临时对象,那就没关系了,因为字符串字段会经常被垃圾收集。但由于对它们的引用被保留,它们的内存使用开始累积(即使没有添加新的唯一值)


因此,对象的内部化大大减少了内存使用,在对象被内部化时,字符串值的内部化也大大减少了内存使用。

字符串的内部化会影响内存消耗

例如,如果您读取字符串并将其保存在列表中以进行缓存;同一个字符串出现10次,如果使用string.Intern,该字符串实际上只在内存中存储一次。如果没有,字符串将存储10次

在下面的示例中,string.Intern变量消耗大约44MB,而不带注释的版本(未注释)消耗1195MB

static void Main(string[] args)
{
    var list = new List<string>();

    for (int i = 0; i < 5 * 1000 * 1000; i++)
    {
        var s = ReadFromDb();
        list.Add(string.Intern(s));
        //list.Add(s);
    }

    Console.WriteLine(Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024 + " MB");
}

private static string ReadFromDb()
{
    return "abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789abcdefghijklmnopqrstuvyxz0123456789" + 1;
}
static void Main(字符串[]args)
{
var list=新列表();
对于(int i=0;i<5*1000*1000;i++)
{
var s=ReadFromDb();
添加(string.Intern);
//列表。添加(s);
}
Console.WriteLine(Process.GetCurrentProcess().privateMorysize64/1024/1024+“MB”);
}
私有静态字符串ReadFromDb()
{
返回“ABCDEFGHIJKLMNOPQRSTUYXZ0123456789ABCDEFGHIJKLMNOPQRSTUYXZ0123456789ABCDEFGHIJKLMNOPQRSTUYXZ0123456789”+1;
}
内部化还提高了对等比较的性能。下面的示例中,实习生版本大约需要1个时间单位,而非实习生版本需要7个时间单位

static void Main(string[] args)
{
    var a = string.Intern(ReadFromDb());
    var b = string.Intern(ReadFromDb());
    //var a = ReadFromDb();
    //var b = ReadFromDb();

    int equals = 0;
    var stopwatch = Stopwatch.StartNew();
    for (int i = 0; i < 250 * 1000 * 1000; i++)
    {
        if (a == b) equals++;
    }
    stopwatch.Stop();

    Console.WriteLine(stopwatch.Elapsed + ", equals: " + equals);
}
static void Main(字符串[]args)
{
var a=string.Intern(ReadFromDb());
var b=string.Intern(ReadFromDb());
//var a=ReadFromDb();
//var b=ReadFromDb();
int等于0;
var stopwatch=stopwatch.StartNew();
对于(int i=0;i<250*1000*1000;i++)
{
如果(a==b)等于++;
}
秒表;
Console.WriteLine(stopwatch.appeased+”,等于:“+equals”);
}

插入字符串具有以下特征:

  • 两个相同的插入字符串在内存中具有相同的地址
  • 在应用程序终止之前,不会释放被插入字符串占用的内存
  • 插入一个字符串需要计算一个散列并在一个消耗CPU周期的字典中查找它
  • 如果多个线程同时插入字符串,它们将互相阻止,因为对插入字符串字典的访问是序列化的
这些特征的后果是:

  • 您可以通过比较地址指针来测试两个内部字符串是否相等,这比比较字符串中的每个字符快得多。如果字符串很长且以相同字符开头,则尤其如此。您可以将插入的字符串与
    对象.ReferenceEquals
    方法进行比较,但使用
    string==
    运算符更安全,因为它会检查字符串是否先插入

  • 如果在应用程序中多次使用同一字符串,应用程序将只在内存中存储该字符串的一个副本,从而减少运行应用程序所需的内存

  • 如果您插入许多不同的字符串,这将为那些永远不会被释放的字符串分配内存,并且您的应用程序将消耗越来越多的内存

  • 如果有大量的内部字符串,则字符串内部处理可能会变慢,并且线程在访问内部字符串字典时会相互阻塞

只有在以下情况下,才应使用字符串插入:

  • 您正在实习的字符串集相当小
  • 每次实习这些字符串时,都要对它们进行多次比较
  • 你真的在乎那一分钟吗