gpt4 book ai didi

c# - ReadOnlySpan 参数是否应使用 "in"修饰符?

转载 作者:太空狗 更新时间:2023-10-30 00:17:57 27 4
gpt4 key购买 nike

引入了 C# 7.2 reference semantics with value-types ,除此之外,微软还开发了类似 Span<T> and ReadOnlySpan<T> 的类型潜在地提高需要在连续内存区域上执行操作的应用程序的性能。

根据文档,一种可能提高性能的方法是通过添加 in 来通过引用传递不可变结构。这些类型的参数修饰符:

void PerformOperation(in SomeReadOnlyStruct value)
{
}

我想知道我是否应该对 ReadOnlySpan<T> 这样的类型执行此操作.我是否应该像这样声明接受只读跨度的方法:

void PerformOperation<T>(in ReadOnlySpan<T> value)
{
}

或简单地喜欢:

void PerformOperation<T>(ReadOnlySpan<T> value)
{
}

前者是否会比后者提供任何性能优势?我找不到任何在这两个方向上明确建议的文档,但我确实找到了 this example他们在那里演示了一种接受 ReadOnlySpan 的方法并且没有使用 in修饰符。

最佳答案

Marc 的回答似乎很准确。我发布这个只是为了用一些基准来补充他自己的答案,这些基准证实了他所说的话。

我设置了以下基准类:

public class SpanBenchmarks
{
private const int Iterations = 100_000;

private byte[] _data;
private LargeStruct _control;

[GlobalSetup]
public void GlobalSetup()
{
_data = new byte[1000];
new Random().NextBytes(_data);

_control = new LargeStruct(_data[0], _data[1], _data[2], _data[3], _data[4], _data[5]);
}

[Benchmark]
public void PassSpanByValue()
{
for (int i = 0; i < Iterations; i++) AcceptSpanByValue(_data);
}

[Benchmark]
public void PassSpanByRef()
{
for (int i = 0; i < Iterations; i++) AcceptSpanByRef(_data);
}

[Benchmark]
public void PassLargeStructByValue()
{
for (int i = 0; i < Iterations; i++) AcceptLargeStructByValue(_control);
}

[Benchmark]
public void PassLargeStructByRef()
{
for (int i = 0; i < Iterations; i++) AcceptLargeStructByRef(_control);
}

private int AcceptSpanByValue(ReadOnlySpan<byte> span) => span.Length;
private int AcceptSpanByRef(in ReadOnlySpan<byte> span) => span.Length;
private decimal AcceptLargeStructByValue(LargeStruct largeStruct) => largeStruct.A;
private decimal AcceptLargeStructByRef(in LargeStruct largeStruct) => largeStruct.A;

private readonly struct LargeStruct
{
public LargeStruct(decimal a, decimal b, decimal c, decimal d, decimal e, decimal f)
{
A = a;
B = b;
C = c;
D = d;
E = e;
F = f;
}

public decimal A { get; }
public decimal B { get; }
public decimal C { get; }
public decimal D { get; }
public decimal E { get; }
public decimal F { get; }
}
}

我用这个重复了 3 次相同的基准测试,每次都得到相似的结果:

BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.248)
Intel Core i7-4790 CPU 3.60GHz (Haswell), 1 CPU, 8 logical cores and 4 physical cores

Frequency=3507500 Hz, Resolution=285.1033 ns, Timer=TSC
.NET Core SDK=2.1.300-preview2-008354
[Host] : .NET Core 2.0.6 (CoreCLR 4.6.26212.01, CoreFX 4.6.26212.01), 64bit RyuJIT
DefaultJob : .NET Core 2.0.6 (CoreCLR 4.6.26212.01, CoreFX 4.6.26212.01), 64bit RyuJIT


Method | Mean | Error | StdDev |
----------------------- |----------:|----------:|----------:|
PassSpanByValue | 641.71 us | 0.1758 us | 0.1644 us |
PassSpanByRef | 642.62 us | 0.1524 us | 0.1190 us |
PassLargeStructByValue | 390.78 us | 0.2633 us | 0.2463 us |
PassLargeStructByRef | 35.33 us | 0.3446 us | 0.3055 us |

使用大型结构作为控件,我确认通过引用而不是通过值传递它们具有显着的性能优势。但是,传递 Span<T> 之间没有显着的性能差异。通过引用或值。


2019 年 9 月更新

出于好奇,我使用 .NET Core 2.2 再次运行相同的基准测试。自上次以来似乎引入了一些巧妙的优化,以减少将数组隐式转换为 Span<T> 的开销。 :

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.17134.984 (1803/April2018Update/Redstone4)
Intel Core i7-4700HQ CPU 2.40GHz (Haswell), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.2.106
[Host] : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), 64bit RyuJIT
DefaultJob : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), 64bit RyuJIT


| Method | Mean | Error | StdDev |
|----------------------- |----------:|----------:|----------:|
| PassSpanByValue | 39.78 us | 0.1873 us | 0.1660 us |
| PassSpanByRef | 41.21 us | 0.2618 us | 0.2186 us |
| PassLargeStructByValue | 475.41 us | 1.3104 us | 1.0943 us |
| PassLargeStructByRef | 39.75 us | 0.1001 us | 0.0937 us |

关于c# - ReadOnlySpan<T> 参数是否应使用 "in"修饰符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49297751/

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