【问题标题】:Is caching strings something to worry about? [duplicate]缓存字符串有什么需要担心的吗? [复制]
【发布时间】:2019-03-12 02:02:53
【问题描述】:

我找不到任何可以明确回答我的问题的东西,所以我想我会问:这是最佳做法还是只是喜欢做类似的事情:

public static class FixedStrings
{
      public static readonly string foo = "bar";
}

class Example1
{
    void UseString()
    {
        Console.WriteLine(FixedStrings.foo);
    }
}

代替:

class Example2
{
    void UseString()
    {
        Console.WriteLine("bar");
    }
}

这是我目前的理解(我可能错了):

  1. 这是内存与 GC 分配的权衡;因此,如果需要字符串的方法经常被调用,或者它处于长时间运行的过程中,那么第一个示例是更好的选择。
  2. 如果内存不是问题,缓存可重复使用的字符串(或任何对象)将减少 GC 花费的时间并提高程序的响应能力。
  3. .NET GC 做得非常好,但是这些字符串中的一些会定期通过代,尤其是在负载下并且在很长一段时间后可能会导致完全 GC 清理。
  4. Example1 在性能方面几乎总是击败 Example2

我注意到来自不同地方的示例代码,人们同时使用这两种方法。我不确定这是否只是因为example2 打字更快,还是因为阅读偏好。我也很好奇,编译器是否足够聪明,可以自动将其中一些字符串转成缓存变量?

请记住,我所说的所有这些都是我从互联网上学到的,我没有受过正规教育。假设example1 更好,我可能是非常错误的

这就是我担心这样一个小优化的原因:

在我的实际项目中并没有那么小;在某些情况下,我可能每秒使用这些字符串数千次。

【问题讨论】:

  • 从技术上讲,如果采用 “是最佳实践还是只是偏好做类似的事情” 的形式,您的问题是不合适的,因为“主要基于意见”。但是,从侧面问题中询问字符串是否被缓存,作为副本关闭似乎也是合理的。有关解决您的整体问题的详细信息,请参阅标记的重复项。
  • 如果您怀疑实际项目中的影响并不小,那么您应该能够衡量这种影响。双向编写代码,双向运行,看看哪个(如果有的话)具有不可接受的性能。如果您无法检测到不可接受的性能,那么......那么我认为它是可以接受的,不是吗?

标签: c# .net string garbage-collection


【解决方案1】:

我也很好奇,编译器是否足够聪明,可以自动将其中一些字符串转换为缓存变量?

是的。如果您在单个程序集中具有相同的字符串文字,则作为一种优化,C# 将仅在运行时创建该字符串的一个实例并将其缓存。这称为“字符串实习”。 This blog post by Eric Lippert 解释了一般原则及其对性能/垃圾收集的影响。

作为字符串实习的结果,假设这些示例中的所有代码都存在于单个程序集中,那么您的两个示例在运行时都只会分配一个字符串。

因此,您遵循哪种模式是风格问题。对于文档和教育中使用的示例,如果字符串与其余代码“一致”,通常更容易阅读,例如示例 2。如果您正在编写一个大型、复杂的程序,其中必须使用完全相同的字符串在多个地方,我更喜欢示例 1。这避免了在每个使用它的地方重新键入字符串 - 可能是错误输入,为代码中的字符串提供一个有意义的名称,并且如果将来的版本中需要更改字符串。

最后,关于你提到的项目。如果您关心的字符串是在编译时定义的(即,它们是像 "My String" 这样的字符串文字),那么 C# 的自动字符串实习可能就足够了。如果您有很多直到运行时才知道的字符串,但您想避免重新分配,您可能需要声明一些东西来保存这些字符串对象以供您的代码以后使用。您使用哪种数据结构取决于您的用例。

您还可以通过调用String.Intern(String) 来强制运行时对字符串进行实习。此方法将给定的字符串放入字符串暂存缓存中(如果它不存在)并从缓存中返回字符串。请注意,您仍然需要以某种方式分配字符串以将其传递给此方法,但该实例的生命周期可能会短很多,因此会使您的项目表现更好。

【讨论】:

    猜你喜欢
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多