string.AsSpan() 与 .NET 中 ReadOnlySpan 的隐式转换运算符性能对比<char>

问题描述 投票:0回答:1

从 .NET 版本开始,我们现在可以从字符串 -> ReadOnlySpan 进行隐式转换。这意味着如果一个函数接受 ReadOnlySpan,我们只需向它传递一个字符串,“转换”就会自动发生。 不过,此隐式运算符在 .NET Standard 2.0 和 .NET Framework 中均不可用...我们正在使用这三个:)

几个问题。

问题 1:为了使我的 .NET 代码符合 .NET Standard 2.0 和 Framework,我可以简单地将 .AsSpan() 调用添加到我的字符串中。然而,这在 .NET(Core)中是“不必要的”,但我的问题是:它的性能是否也更差?或者 .AsSpan() 扩展和隐式运算符是否在幕后执行相同的操作?

问题 2:总的来说,.AsSpan() 和隐式转换是否在堆上分配内存?当然,首先分配调用它的字符串,但是除了 Span 本身的小堆栈分配之外,强制转换或 .AsSpan() 是否会导致任何额外的内存或性能影响?

问题3:是否有创建ReadOnlySpan的“更好的方法”?目前我主要通过字符串 -> 隐式运算符来完成此操作。在一种情况下,我有一个自己的 ref 结构,它始终保存“常量”的 ReadOnlySpan 分隔符。为了在我的结构中拥有这个“常量(只读)”,我必须从字符串或字符数组(我使用字符数组)初始化它。该字段仅包含 2 个字符,使用 stackalloc 将这个小 Span 放入堆栈会更好吗?我没有这样做的原因是因为我必须在经常调用的函数范围内执行此操作,并且我不知道这是否明智(进行大量堆栈分配,尽管它们不在相同或并发的函数调用)?

c# .net performance heap-memory .net-standard-2.0
1个回答
1
投票
  1. 源代码可以看到,对于

    implicit
    运算符执行以下代码:

    public static implicit operator ReadOnlySpan<char>(string? value) =>
            value != null ? new ReadOnlySpan<char>(ref value.GetRawStringData(), value.Length) : default;
    

    扩展方法可以做到这一点

    public static ReadOnlySpan<char> AsSpan(this string? text)
    {
        if (text == null)
            return default;
    
        return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
    }
    

    实际上是完全相同的代码。这些之间的性能绝对没有区别。

  2. 不,没有堆分配。 A

    Span
    ReadOnlySpan
    ref struct
    ,因此即使您尝试(例如将它们装箱),它们也不能分配在堆上,这是不允许的.

  3. 假设

    char
    数组是
    static
    (或者
    string
    来自常量值),可能您已经在使用最有效的分配方法。它不需要保留任何堆栈空间,它只需从现有数组中取出一个
    Span
    即可。
    stackalloc
    则表示每次都需要将数据复制进去。而且
    stackalloc
    在循环中使用时也会产生严重影响,通常会导致堆栈溢出。

© www.soinside.com 2019 - 2024. All rights reserved.