اصلاحیه: کارآیی spread operator بیشتر نیست!
در متن در مورد spread operator عنوان شده «که ... نگارش C# 12 آن کارآیی بیشتری دارد». این مورد بدون توجه به #Low-Level C تولیدی، نوشته شد و ... متاسفانه نادرست است!
برای مثال فرض کنید، چنین متدی را دارید که با استفاده از spread operator، کار بازکردن یک آرایه را انجام میدهد:
public int[] WithSpread()
{
int[] data = new int[10_000];
int[] results = [..data];
return results;
}
معادل #Low-Level C آن (کد نهایی که کامپایلر برای تبدیل آن به IL تولید میکند) به صورت زیر است (
#Low-Level C را در Rider، در منوی #Tools -> IL Viewer -> Select Low-Level C میتوانید تولید کنید):
public int[] WithSpread()
{
int[] numArray1 = new int[10000];
int index1 = 0;
int[] numArray2 = new int[numArray1.Length];
int[] numArray3 = numArray1;
for (int index2 = 0; index2 < numArray3.Length; ++index2)
{
int num = numArray3[index2];
numArray2[index1] = num;
++index1;
}
return numArray2;
}
همانطور که مشاهده میکنید، این قطعه کد در C#12 و داتنت 8، به شدت ابتدایی تولید شده و به همراه هیچ نوع بهینه سازی نیست. کارآیی این قطعه کد، نسبت به زمانیکه از متد قدیمی CopyTo آرایهها استفاده میشود، به مراتب کمتر است (تا 3 برابر!)؛ چون متد CopyTo به همراه بهینه سازیهای سختافزاری هم هست. به نظر قرار شده بهینه سازی کارآیی spread operator در نگارش بعدی داتنت انجام شود.
برای آزمایش شخصی آن، از کلاس زیر استفاده کنید:
using BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpreadBenchmark
{
[MemoryDiagnoser]
public class Tests
{
private readonly int[] _myData = new int[10_000];
[Benchmark(Baseline = true)]
public int[] WithToArray()
{
int[] results = _myData.ToArray();
return results;
}
[Benchmark]
public int[] WithCopyTo()
{
int[] results = new int[_myData.Length];
_myData.CopyTo(results, 0);
return results;
}
[Benchmark]
public int[] WithSpread()
{
int[] results = [.._myData];
return results;
}
}
}
که در فایل Program.cs به این صورت فراخوانی میشود:
using BenchmarkDotNet.Running;
using SpreadBenchmark;
BenchmarkRunner.Run<Tests>();
با این وابستگی:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
</ItemGroup>
</Project>