.NET与Java的子串运算性能比较

Posted

技术标签:

【中文标题】.NET与Java的子串运算性能比较【英文标题】:Comparison of substring operation performance between .NET and Java 【发布时间】:2011-03-29 07:45:56 【问题描述】:

获取字符串的子字符串是一种非常常见的字符串操作操作,但我听说 Java 和 .NET 平台之间的性能/实现可能存在相当大的差异。具体来说,我听说在 Java 中,java.lang.Stringsubstring 提供常量 时间操作,但在.NET 中,System.String 提供线性 性能Substring

真的是这样吗?这可以在文档/源代码等中确认吗?这个实现是特定的,还是由语言和/或平台指定的?每种方法的优缺点是什么?从一个平台迁移到另一个平台的人应该注意什么以避免陷入任何性能陷阱?

【问题讨论】:

为什么不运行您自己的微基准测试来测试呢?你能链接到说它性能“差”的来源吗? @Oded:来源是 Danny Chen 的评论***.com/questions/3474254/…;老实说,如果Substring 不是O(1) 时间和空间操作(例如Java),我会感到惊讶,但由于我不了解.NET,所以我给了他怀疑的好处。 “表现不佳”是什么意思?相对于什么?例如,如果与 C++ 相比,.NET 的性能也很差。我们应该因此放弃 .NET 吗? 这是在引用文章吗?如果是这样,一个链接会非常非常有帮助...... 糟糕 - 我没有看到你之前的评论。 【参考方案1】:

据此并非如此: C# Substring

【讨论】:

【参考方案2】:

使用反射器,这是您从 Substring(Int32, Int32) 得到的结果

[SecuritySafeCritical, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public string Substring(int startIndex, int length)

    return this.InternalSubStringWithChecks(startIndex, length, false);

如果你继续往里走,最后一个电话是给一个

internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)

使用指针复制字符。 完整的代码实际上看起来很大,但在运行它并对其进行基准测试之前,您不会看到它有多快或多慢。

【讨论】:

【参考方案3】:

这真的取决于你的工作量。如果您正在循环并进行大量子字符串调用,那么您可能会遇到问题。对于您所指的 SO 帖子,我怀疑它永远不会成为问题。然而,以这种态度,你总是可能陷入“千刀万剐”的境地。在您提到的 SO 帖子中,我们有以下内容:

String after = before.Substring(0, 1).ToUpper() + before.Substring(1);

假设编译器没有进行一些疯狂的优化,这将创建至少四个新字符串(2 个Substring 调用、一个ToUpper 调用和串联)。子字符串完全按照您的预期实现(字符串复制),但是上面分配的三个字符串很快就会变成垃圾。这样做会产生不必要的内存压力。我说“不必要”是因为您可能只需多花一点时间就可以想出一个更经济的解决方案。

归根结底,分析器是你最好的朋友 :)

【讨论】:

【参考方案4】:

在 .NET 中,Substring 是 O(n) 而不是 Java 的 O(1)。这是因为在 .NET 中,String 对象包含所有实际的字符数据本身1 - 因此获取子字符串涉及复制新子字符串中的所有数据。在 Java 中,substring 可以创建一个引用原始 char 数组的新对象,具有不同的起始索引和长度。

每种方法各有利弊:

.NET 的方法具有更好的缓存一致性,创建的对象更少2,并且避免了一个小的子字符串阻止非常大的char[] 被垃圾回收的情况。我相信在某些情况下,它也可以在内部使互操作变得非常容易。 Java 的方法使得获取子字符串非常高效,可能还有其他一些操作

在我的strings article 中有更多细节。

至于避免性能陷阱的一般问题,我认为我应该准备好剪切和粘贴的固定答案:确保您的架构是高效的,并以您最易读的方式实现它能够。衡量性能,优化发现瓶颈的地方。


1 顺便说一下,这使得string 非常特别——它是唯一一个内存占用在同一个 CLR 中因实例而异的非数组类型。

2 对于小字符串,这是一个很大的胜利。 one 对象的所有开销已经够糟糕了,但是当涉及到一个额外的数组时,在 Java 中单个字符串可能需要大约 36 个字节。 (这是一个“空中手指”数字 - 我不记得确切的对象开销。它还取决于您使用的虚拟机。)

【讨论】:

以上是关于.NET与Java的子串运算性能比较的主要内容,如果未能解决你的问题,请参考以下文章

.NET番外篇Rust环境搭建+基础开发入门+Rust与.NET6C++的基础运算性能比较

Java中arraylist和linkedlist源码分析与性能比较

比较运算符的性能(>、>=、<、<=)

使用比较运算符时的 MYSQL 性能

.NET和Java的应用和前景

用 Pl/SQL 与 Java 编写的存储过程的性能比较