Span์ Memory์ ๋ํด ๊ธฐ๋ก์ ๋จ๊ธฐ๋ ค ํฉ๋๋ค. ์ฒ์ ๋ฑ์ฅํ์ ๋ ์ต์ํด์ง๋ ค๊ณ ๋ ธ๋ ฅํ๋ค๊ฐ ์คํจํ๋๋ฐ, ์ต์ํด์ง๋ค๋ฉด ์์ฐ์ค๋ฝ๊ฒ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ์ต๊ด, ๋น๊ด๋ฆฌ๋ฉ๋ชจ๋ฆฌ์ ํจ๊ณผ์ ์ธ ์ ๊ทผ, ๋ช ์ธ ํํ์ผ๋ก ๊ด๋ จ ๋ฒ๊ทธ๋ฅผ ์ต์ํ ํจ ๋ฑ ๋ค์ํ ์ฅ์ ์ด ๊ธฐ๋๋๋ฏ๋ก, ๊ด๋ จ ์ ๋ณด๋ค์ ์์ง ํ ํ ์ค์ต์ ํตํด ์ตํ๋๊ฐ๋ด ์๋ค
์ ์ฑํ๋์ด ์ ๋ฆฌํ ๋ด์ฉ์ ๊ณต์ ํฉ๋๋ค. ์ ์ฑํ๋์ ๊ธ์ ์ฒ ์ ํ ๊ฒ์ฆํ์ฌ ์์ฑ๋ ๊ธ์ด๊ธฐ ๋๋ฌธ์ ๋์์ด ๋ฉ๋๋ค.
.NET Framework: 758. C# 7.2 - Span (sysnet.pe.kr)
.NET Framework: 759. C# - System.Span ์ฑ๋ฅ (sysnet.pe.kr)
.NET Framework: 768. BenchmarkDotNet์ผ๋ก Span ์ฑ๋ฅ ์ธก์ (sysnet.pe.kr)
.NET Framework: 995. C# - Span์ Memory (sysnet.pe.kr)
jacking75๋์ด ๋ฒ์ญํ์ ๋ด์ฉ๋ ์ข์ต๋๋ค.
Span์ ref struct
์ด๊ธฐ ๋๋ฌธ์ ์คํ์๋ง ํ ๋นํ ์ ์์ต๋๋ค. ๋ค์์ ์ฑํ๋ ์ ๋ฆฌ๋ก ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
- ํ์์๋ ์ฑ๋ฅ์ ์ํด Span๋ฅผ ์ฌ์ฉํ๊ณ , 2) ๊ฐํน ํด๋น ๋ฒํผ๋ฅผ ๋ค๋ฅธ ํ์ ์ ํ๋๋ก ๋ค๊ณ ์์ด์ผ ํ ๋ Memory๋ฅผ ์ฌ์ฉํ๋ค๊ฐ, 3) ๋ค์ ๊ทธ๊ฒ์ ์ ๊ทผํด์ผ ํ ๋๋ Span๋ก ์บ์ํด ์ฌ์ฉํ๋ ๊ฒ
Span๋ฐ Memory๋ ์ธ์ ํ ์์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ํด ํ์ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์์ ํํ์ ์ ๊ณตํฉ๋๋ค.
์ด์ ๋ฐํด ReadOnlySequence๋ ๋ถ์ฐ์์ ์ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํฉ์ณ์ ์์ฐจ์ ์ธ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋๋ก ํฉ๋๋ค.
๋ด์ฉ ๊ฐ์ฌํฉ๋๋ค.
๋์์ผ๋ก ์ ์ค๋ช ๋ ์ข์ ๊ธ์ ๋งํฌ ํฉ๋๋ค. ๋ด์ฉ ์์ผ๋ฏ๋ก ์ฐฌ์ฐฌํ ์๊ฐ์ ๋๊ณ ์ฝ์ผ์๋ฉด ๋์์ด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
New NET Core 2.1 Flagship Types: Span and Memory (codemag.com)
์ ์ฑํ๋์
.NET Framework: 768. BenchmarkDotNet์ผ๋ก Span ์ฑ๋ฅ ์ธก์ (sysnet.pe.kr)
๋ฒค์น๋งํฌ ์ฝ๋๋ฅผ ์ด์ฉํ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Span๋ ๋น๊ด๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ฐฐ์ด์ฒ๋ผ ์ ๊ทผํ ์ ์๋ค๋ ์ฅ์ ๋ ์์ง๋ง, ๋ฐ์ดํธ ๋ฐฐ์ด์ ๋น์ฉ์์ด ์ชผ๊ฐค ์ ์์ง๋ง, Span๋ ํ์ํ ์์ญ๋ง ์๋ผ ์ธ ์ ์๊ณ ๋น์ฉ ๋ํ ์๋ค๋๊ฒ ์ฅ์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
(byte[], offset, length) buffer ๋ณด๋ค๋ Span buffer๊ฐ ์ฝ๋๋ ๊น๋ํ๊ณ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ์ฌ์ง๊ฐ ์ ๋ค๋ ๊ฒ์ด์ฃ .
์ด ๊ธ์ด ์ ์๊ฒ ์ค์ง์ ์ผ๋ก ๋์์ด ๋์ต๋๋ค. ๊ฐ๋ ์ ์ผ๋ก ์ดํดํ๋ ๊ฒ๊ณผ ์์ด ๋๊ฐ๋ ๊ฒ์ ์กฐ๊ธ ๋ค๋ฅธ ๊ฐ๊ฐ์ธ ๊ฒ ๊ฐ๋ค์. ๋ง์น ์์ด์ ๋ ํด์ ํํ ๊ฐ์ด์.
์ฐธ๊ณ ํ์ฌ Span ํ์ฅ ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ดค์ต๋๋ค. ๊ฐ์ด ๋ณด์์ฃ .
public static class SpanExtension
{
public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this ref T @this)
where T : struct
{
var span = MemoryMarshal.CreateReadOnlySpan(ref @this, 1);
return MemoryMarshal.Cast<T, byte>(span);
}
public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this T[] @this)
where T : struct
{
return MemoryMarshal.Cast<T, byte>(@this);
}
public static Span<byte> AsBytes<T>(this ref T @this)
where T : struct
{
var span = MemoryMarshal.CreateSpan(ref @this, 1);
return MemoryMarshal.Cast<T, byte>(span);
}
public static Span<byte> AsBytes<T>(this T[] @this)
where T : struct
{
return MemoryMarshal.Cast<T, byte>(@this);
}
}
ํ์ฅ์ ๋ณด์๋ฉด MemoryMarshal์ ๊ธฐ๋ฅ์ ์ด์ฉํ ๊ฒ ๋ฟ์ด์ง๋ง, ๊ฐ๋ ฅํฉ๋๋ค. ์ด ํ์ฅ์ ์ด์ฉํด ๋ค์๊ณผ ๊ฐ์ด Stream์ ์ฐ๊ฑฐ๋ ์ฝ๋ ์ฝ๋๋ฅผ ๋จ์ํ ํ์์ต๋๋ค.
public void Write(Stream s)
{
s.Write(์ฒด๊ฒฐ์๊ฐ.AsReadOnlyBytes());
s.Write(์ฒด๊ฒฐ๊ฐ.AsReadOnlyBytes());
s.Write(์ฒด๊ฒฐ์๋.AsReadOnlyBytes());
s.Write(๋งค์ํธ๊ฐ์๋.AsReadOnlyBytes());
s.Write(๋งค๋ํธ๊ฐ์๋.AsReadOnlyBytes());
}
public static bool Read(Stream s, ref ์ค์๊ฐ์์ธ v)
{
var length = s.Read(v.์ฒด๊ฒฐ์๊ฐ.AsBytes());
if (length == 0)
return false;
s.Read(v.์ฒด๊ฒฐ๊ฐ.AsBytes());
s.Read(v.์ฒด๊ฒฐ์๋.AsBytes());
v.๋งค์ํธ๊ฐ์๋ = new decimal[5];
s.Read(v.๋งค์ํธ๊ฐ์๋.AsBytes());
v.๋งค๋ํธ๊ฐ์๋ = new decimal[5];
s.Read(v.๋งค๋ํธ๊ฐ์๋.AsBytes());
return true;
}
AsReadOnlyBytes()
๋ฅผ ํตํด ๋ฉ๋ชจ๋ฆฌ ํ ๋น ์์ด ํด๋น ํ๋๋ฅผ ReadOnlySpan๋ก ๋ณํํ์ฌ ์ฐ๊ธฐ๋ฅผ ํฉ๋๋ค.
๋์ฑ ์ฌ๋ฐ๋ ๊ฒ์ AsBytes()
๋ฅผ ํตํด ํด๋น ํ๋์ ๋ฉ๋ชจ๋ฆฌ ์์น๋ฅผ Span๋ก ๋ณํํ์ฌ ๋ฐ๋ก ์ฝ๊ธฐํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
ํธ๊ฐ๋ ๋ฐฐ์ด์ธ๋ฐ ํ ๋น์ ๋ณ๋๋ก ํด์ผ ํ๋ ์ด์ ๋ C#์ ๋ฐฐ์ด์ ์ฐธ์กฐ๊ธฐ ๋๋ฌธ์ ๋๋ค. 'fixedโ๋ฅผ ์ฐ๋ฉด ๋๋๋ฐ 'unsafeโ๋ผ ์ผ๋ฐ์ ์ผ๋ก๋ ์ ์์ฐ๋๊ฒ ๊ฐ์ต๋๋ค
์ฌ๋ผ์ด์ฑ์ ๊ฐ๋ ฅํจ์ ์ค๋ช ํ ๊ธ์ ๋๋ค.
์์์ค์๊ฐ์์ธ 1Gbytes (500๋ง๊ฐ)๋ฅผ ์ฝ๋ ์ฝ๋์ ๋๋ค. ์ด๋น ํ๊ฐ์ฉ ๋ฐ์ํ๋ค๊ณ ํ ๋, ๋๋ต 60์ผ ์ ๋์ ๋ฐ์ดํฐ๊ฐ ๋ฉ๋๋ค. ํฅ๋ฏธ๋ก์ด ๊ฒ์ List๋ก ๋ชฉ๋ก์ ์ทจํฉํ๋๋ผ๋ T[]๊ณผ ํฐ ์ฐจ์ด๊ฐ ๋์ง ์์ต๋๋ค. List๊ฐ ์ต์ ํ ๋์ด ์๋ค๋ ๊ฒ์ด๊ฒ ์ฃ
void ์์์์ธ๋ชฉ๋ก_์ฝ๊ธฐ()
{
var filename = "์ค์๊ฐ์์ธ.dat";
using var fs = File.OpenRead(filename);
var length = fs.Length;
var itemCount = length / Marshal.SizeOf<์ค์๊ฐ์์ธ>();
Console.WriteLine($"File Length: {length}");
Console.WriteLine($"Count: {itemCount}");
var v = new ์ค์๊ฐ์์ธ();
//var ์ค์๊ฐ์์ธ๋ชฉ๋ก = new List<์ค์๊ฐ์์ธ>();
var ์ค์๊ฐ์์ธ๋ชฉ๋ก = new ์ค์๊ฐ์์ธ[itemCount];
var count = 0;
var sw = Stopwatch.StartNew();
while (count < itemCount)
{
//var result = ์ค์๊ฐ์์ธ.Read(fs, ref ์ค์๊ฐ์์ธ๋ชฉ๋ก[count]);
var result = ์ค์๊ฐ์์ธ.Read(fs, ref v);
if (result == false)
break;
//์ค์๊ฐ์์ธ๋ชฉ๋ก.Add(v);
์ค์๊ฐ์์ธ๋ชฉ๋ก[count] = v;
count++;
}
sw.Stop();
// List<T> : 2571 ms
// T[], ์คํ ์์๊ฐ ์ ์ฅ ํ ๋ณต์ฌ : 2354 ms
// T[], ์ง์ ์ ์ฅ : 2339 ms
Console.WriteLine($"Elapsed Time: {sw.ElapsedMilliseconds}");
}
์กฐ๊ธ ๋ ๋ค๋ฅธ ์ ๊ทผ์ ํด๋ดค์ต๋๋ค. ๋ง์ฝ, MemoryMappedFile
์ ์ด์ฉํด Span<byte>
์ ํ๋ํ ์ ๋ง ์๋ค๋ฉด, ์ข ๋ ํจ์จ์ ์ธ ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์์๊บผ๋ผ ์๊ฐํ์ต๋๋ค.
ํ์ธํ ๊ฒฐ๊ณผ, ์ด์ฉ ์ ์์ด unsafe
์์ญ์ ์ฌ์ฉํด์ผ ํ๊ณ , decimal
์ด ๊ณ ์ ๋ฐฐ์ด์ด ์๋๋ค๋ ์ฌ์ค๋ ์๊ฒ ๋์์ง๋ง, ์ด์จ๋ ์๋นํ ๋น ๋ฅธ ์๋๋ก ๋ชฉ๋ก(Span<์ค์๊ฐ์์ธ2>
)์ ์์ฑํ ์ ์์์ต๋๋ค.
void ์์์์ธ๋ชฉ๋ก_์ฝ๊ธฐ2()
{
var filename = "์ค์๊ฐ์์ธ.dat";
var fileLength = new FileInfo(filename).Length;
using var mmf = MemoryMappedFile.CreateFromFile(filename, FileMode.Open);
using var accessor = mmf.CreateViewAccessor();
Span<byte> memory;
unsafe
{
byte* ptr = null;
accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
ptr += accessor.PointerOffset;
//memory = new Span<byte>(ptr, (int)accessor.SafeMemoryMappedViewHandle.ByteLength);
memory = new Span<byte>(ptr, (int)fileLength);
}
var ์ค์๊ฐ์์ธ๋ชฉ๋ก = MemoryMarshal.Cast<byte, ์ค์๊ฐ์์ธ2>(memory);
foreach (var item in ์ค์๊ฐ์์ธ๋ชฉ๋ก)
{
;
}
accessor.SafeMemoryMappedViewHandle.ReleasePointer();
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct ์ค์๊ฐ์์ธ2
{
public long ์ฒด๊ฒฐ์๊ฐ;
public decimal ์ฒด๊ฒฐ๊ฐ;
public decimal ์ฒด๊ฒฐ์๋;
public fixed int _๋งค์ํธ๊ฐ์๋[4 * 5];
public fixed int _๋งค๋ํธ๊ฐ์๋[4 * 5];
}
TLS๋ก ์คํ๋๋ ์ฝ๋ ๊ณต์ ํฉ๋๋ค. ์ด๊ฒ์ผ๋ก Span<T>
์ ๋ํ ๊ณต๋ถ๋ ๋ง๋ฌด๋ฆฌ ํ๊ณ , ๋ค์๋ฒ์ Memory<T>
๋ฐ Memory<T>
์ ๊ด๋ จ๋ .NET ๊ธฐ๋ฅ๋ค์ ์ดํด๋ณผ ์์ ์
๋๋ค.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ๋ชจ๋ ์์ ๋ Top-level-statements(TLS)๋ก ์์ฑํฉ๋๋ค.
// ์ ๋ชฉ: ๋์ฉ๋ ํ์ผ ๋ฐ์ดํฐ๋ฅผ .NET C#์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ
// ์ฃผ์ : ์์ฃผ ํฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ค๊ณ ํ ๋ .NET์์ ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ์ฐพ๋๋ค.
// ์ ์ : 1) ์ฃผ์ ์ค์๊ฐ ์์ธ ๋ชฉ๋ก์ด ์๋ค๊ณ ๊ฐ์ ํ๋ค. ์ด ์์ธ๋ ์์๋ก ์ฝ 1Gbytes๋ฅผ ์์ฑํด๋๋ค.
// 2) ํ๋์ ์์ธ๋ ์ ์ ๊ธธ์ด๋ฅผ ๊ฐ๋๋ค.
// ์งํ: 0) ์์์ ์ค์๊ฐ ์์ธ ์ ๋ณด๋ฅผ ํ์ผ๋ก ์ ์ฅํ๋ค. (1Gbytes)
// 1) ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ FileStream์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
// X 2) ๊ทน์ ์ธ ์๋ ํฅ์์ ์ํด ์ค์๊ฐ ์์ธ๋ฅผ ๋ฉ๋ชจ๋ฆฌ๋ก ์ฌ๋ฆฐ ํ Memory<T>๋ฅผ ์ด์ฉํด์ ๊ตฌํํ๋ค.
// 3) MemoryMappedFile์ ์ด์ฉํด์ ๊ตฌํํ๋ค.
์์์์ธ๋ชฉ๋ก_๋ง๋ค๊ธฐ();
์์์์ธ๋ชฉ๋ก_์ฝ๊ธฐ2();
void ์์์์ธ๋ชฉ๋ก_๋ง๋ค๊ธฐ()
{
var filename = "์ค์๊ฐ์์ธ.dat";
if (File.Exists(filename) == true)
return;
var now = DateTime.Now;
var v = new ์ค์๊ฐ์์ธ
{
์ฒด๊ฒฐ์๊ฐ = now.ToBinary(),
์ฒด๊ฒฐ๊ฐ = 15000,
์ฒด๊ฒฐ์๋ = 100,
๋งค์ํธ๊ฐ์๋ = new decimal[] { 1, 2, 3, 4, 5 },
๋งค๋ํธ๊ฐ์๋ = new decimal[] { 11, 22, 33, 44, 55 }
};
// Unsafe.Sizeof<T>๋ก๋ ์ฌ์ด์ฆ๋ฅผ ์ ์ ์์ผ๋, ์ฐธ์กฐํ์ ๊ฒฝ์ฐ ์ฐธ์กฐ ์ฌ์ด์ฆ๋ ๊ณ์ฐํด์ผ ํ๋ฏ๋ก Marshal.SizeOf<T>๋ฅผ ์ฌ์ฉ ํจ
var count = 1000 * 1000 * 1000 / Marshal.SizeOf<์ค์๊ฐ์์ธ>();
Console.WriteLine($"Marshal SizeOf: {Marshal.SizeOf<์ค์๊ฐ์์ธ>()} bytes");
Console.WriteLine($"Unsafe SizeOf: {Unsafe.SizeOf<์ค์๊ฐ์์ธ>()} bytes");
Console.WriteLine($"Count: {count}");
using var fs = File.OpenWrite(filename);
for (var i = 0; i < count; i++)
{
v.์ฒด๊ฒฐ์๊ฐ += 1;
v.์ฒด๊ฒฐ์๋ += 1;
v.Write(fs);
}
fs.Dispose();
var fi = new FileInfo(filename);
Console.WriteLine($"File Length : {fi.Length} bytes");
}
#pragma warning disable CS8321 // ๋ก์ปฌ ํจ์๊ฐ ์ ์ธ๋์์ง๋ง ์ฌ์ฉ๋์ง ์์
void ์์์์ธ๋ชฉ๋ก_์ฝ๊ธฐ()
#pragma warning restore CS8321 // ๋ก์ปฌ ํจ์๊ฐ ์ ์ธ๋์์ง๋ง ์ฌ์ฉ๋์ง ์์
{
var filename = "์ค์๊ฐ์์ธ.dat";
using var fs = File.OpenRead(filename);
var length = fs.Length;
var itemCount = length / Marshal.SizeOf<์ค์๊ฐ์์ธ>();
Console.WriteLine($"File Length: {length}");
Console.WriteLine($"Count: {itemCount}");
var v = new ์ค์๊ฐ์์ธ();
//var ์ค์๊ฐ์์ธ๋ชฉ๋ก = new List<์ค์๊ฐ์์ธ>();
var ์ค์๊ฐ์์ธ๋ชฉ๋ก = new ์ค์๊ฐ์์ธ[itemCount];
var count = 0;
var sw = Stopwatch.StartNew();
while (count < itemCount)
{
//var result = ์ค์๊ฐ์์ธ.Read(fs, ref ์ค์๊ฐ์์ธ๋ชฉ๋ก[count]);
var result = ์ค์๊ฐ์์ธ.Read(fs, ref v);
if (result == false)
break;
//์ค์๊ฐ์์ธ๋ชฉ๋ก.Add(v);
์ค์๊ฐ์์ธ๋ชฉ๋ก[count] = v;
count++;
}
sw.Stop();
// List<T> : 2571 ms
// T[], ์คํ ์์๊ฐ ์ ์ฅ ํ ๋ณต์ฌ : 2354 ms
// T[], ์ง์ ์ ์ฅ : 2339 ms
Console.WriteLine($"Elapsed Time: {sw.ElapsedMilliseconds}");
}
/// <summary>
/// MemoryMappedFile๋ก Span<byte> -> Span<์ค์๊ฐ์์ธ>๋ก ๋ณํํ์ฌ ์ง์ ์ ๊ทผ
/// </summary>
void ์์์์ธ๋ชฉ๋ก_์ฝ๊ธฐ2()
{
var filename = "์ค์๊ฐ์์ธ.dat";
var fileLength = new FileInfo(filename).Length;
using var mmf = MemoryMappedFile.CreateFromFile(filename, FileMode.Open);
using var accessor = mmf.CreateViewAccessor();
Span<byte> memory;
unsafe
{
byte* ptr = null;
accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
ptr += accessor.PointerOffset;
//memory = new Span<byte>(ptr, (int)accessor.SafeMemoryMappedViewHandle.ByteLength);
memory = new Span<byte>(ptr, (int)fileLength);
}
var ์ค์๊ฐ์์ธ๋ชฉ๋ก = MemoryMarshal.Cast<byte, ์ค์๊ฐ์์ธ2>(memory);
foreach (var item in ์ค์๊ฐ์์ธ๋ชฉ๋ก)
{
;
}
accessor.SafeMemoryMappedViewHandle.ReleasePointer();
}
/// <summary>
/// C#์ ๋ฐฐ์ด์ ์ฐธ์กฐ์ด๋ฏ๋ก, MemoryMappedFile์์ ์ฌ์ฉํ๊ธฐ ์ํด ๊ณ ์ ๋ฐฐ์ด๋ก ์ ๊ทผ
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct ์ค์๊ฐ์์ธ2
{
public long ์ฒด๊ฒฐ์๊ฐ;
public decimal ์ฒด๊ฒฐ๊ฐ;
public decimal ์ฒด๊ฒฐ์๋;
public fixed int _๋งค์ํธ๊ฐ์๋[4 * 5];
public fixed int _๋งค๋ํธ๊ฐ์๋[4 * 5];
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ์ค์๊ฐ์์ธ
{
public long ์ฒด๊ฒฐ์๊ฐ;
public decimal ์ฒด๊ฒฐ๊ฐ;
public decimal ์ฒด๊ฒฐ์๋;
// Marshal.Sizeof ๊ณ์ฐ ์ฉ๋
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public decimal[] ๋งค์ํธ๊ฐ์๋;
// Marshal.Sizeof ๊ณ์ฐ ์ฉ๋
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public decimal[] ๋งค๋ํธ๊ฐ์๋;
public void Write(Stream s)
{
s.Write(์ฒด๊ฒฐ์๊ฐ.AsReadOnlyBytes());
s.Write(์ฒด๊ฒฐ๊ฐ.AsReadOnlyBytes());
s.Write(์ฒด๊ฒฐ์๋.AsReadOnlyBytes());
s.Write(๋งค์ํธ๊ฐ์๋.AsReadOnlyBytes());
s.Write(๋งค๋ํธ๊ฐ์๋.AsReadOnlyBytes());
}
public static bool Read(Stream s, ref ์ค์๊ฐ์์ธ v)
{
var length = s.Read(v.์ฒด๊ฒฐ์๊ฐ.AsBytes());
if (length == 0)
return false;
s.Read(v.์ฒด๊ฒฐ๊ฐ.AsBytes());
s.Read(v.์ฒด๊ฒฐ์๋.AsBytes());
v.๋งค์ํธ๊ฐ์๋ = new decimal[5];
s.Read(v.๋งค์ํธ๊ฐ์๋.AsBytes());
v.๋งค๋ํธ๊ฐ์๋ = new decimal[5];
s.Read(v.๋งค๋ํธ๊ฐ์๋.AsBytes());
return true;
}
}
/// <summary>
/// Span ํ์ฅ
///
/// MemoryMarshal.Cast<T, byte>(span)์ ๊ฒฝ์ฐ MemoryMarshal.AsBytes(span)์ ๋์ ์ฌ์ฉํ ์ ์์
/// </summary>
public static class SpanExtension
{
public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this ref T @this)
where T : struct
{
var span = MemoryMarshal.CreateReadOnlySpan(ref @this, 1);
return MemoryMarshal.Cast<T, byte>(span);
}
public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this T[] @this)
where T : struct
{
return MemoryMarshal.Cast<T, byte>(@this);
}
public static Span<byte> AsBytes<T>(this ref T @this)
where T : struct
{
var span = MemoryMarshal.CreateSpan(ref @this, 1);
return MemoryMarshal.Cast<T, byte>(span);
}
public static Span<byte> AsBytes<T>(this T[] @this)
where T : struct
{
return MemoryMarshal.Cast<T, byte>(@this);
}
}
Span<T>
์ ์คํ์๋ง ์์ฑํ ์ ์์ด์ ์๋์ ์ค๋ ๋ ์์ ์ฑ์ ํ๋ณดํ ์ ์์๋ ๋์ ๊ด๋ฆฌํ์ ์ ์ฌํ ์ ์๋ ๋จ์ ์ด ์๋๋ฐ, Memory<T>
๋ struct
์ผ๋ก ๊ด๋ฆฌํ์ ์ ์ฌ๊ฐ ๋๊ธฐ ๋๋ฌธ์, ์ฐ์๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณ์ ์ ์งํ ์ ์์ต๋๋ค.
ํ์ง๋ง ํ ๋ฉ๋ชจ๋ฆฌ์ ์์ ์ ์๋ค๋ ๊ฒ์ ๋ค์ค ์ค๋ ๋์์ Memory<T>
์ ์ ๊ทผ ํ ์ ์๋ค๋ ์ด์ผ๊ธฐ ์ธ๋ฐ์, ๊ทธ๋์ Memory<T>
์๋ ์์ ์/์๋น์ ๋ชจ๋ธ์ด ๋ฑ์ฅํฉ๋๋ค.
Memory ๋ฐ Span ์ฌ์ฉ ์ง์นจ | Microsoft Docs
๊ท์น #1: ๋๊ธฐ API์ ๊ฒฝ์ฐ ๊ฐ๋ฅํ๋ฉด Memory ๋์ Span๋ฅผ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉํฉ๋๋ค.
๊ท์น #2: ๋ฒํผ๊ฐ ์ฝ๊ธฐ ์ ์ฉ์ด์ด์ผ ํ๋ ๊ฒฝ์ฐ ReadOnlySpan ๋๋ ReadOnlyMemory ์ฌ์ฉ ์ ์ฐธ์กฐํ์ธ์.
๊ท์น #3: ๋ฉ์๋๊ฐ Memory๋ฅผ ์ฌ์ฉํ๊ณvoid
๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ ๋ฉ์๋๊ฐ ๋ฐํ๋ ํ์๋ Memory ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ฉ๋๋ค.
๊ท์น #4: ๋ฉ์๋๊ฐ Memory๋ฅผ ์ฌ์ฉํ๊ณ Task๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ, Task๊ฐ ํฐ๋ฏธ๋ ์ํ๋ก ์ ํ๋ ํ์๋ Memory ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ฉ๋๋ค.
๊ท์น #5: ์์ฑ์๊ฐ Memory๋ฅผ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์์ฑ๋ ๊ฐ์ฒด์ ์ธ์คํด์ค ๋ฉ์๋๊ฐ Memory ์ธ์คํด์ค์ ์๋น์๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
๊ท์น #6: ์ค์ ๊ฐ๋ฅํ Memory ํ์์ ์์ฑ(๋๋ ๋๋ฑํ ์ธ์คํด์ค ๋ฉ์๋)์ด ํ์์ ์๋ ๊ฒฝ์ฐ ํด๋น ๊ฐ์ฒด์ ์ธ์คํด์ค ๋ฉ์๋๋ Memory ์ธ์คํด์ค์ ์๋น์๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
๊ท์น #7: IMemoryOwner ์ฐธ์กฐ๊ฐ ์๋ ๊ฒฝ์ฐ ์ผ์ ์์ ์์ ์ญ์ ํ๊ฑฐ๋ ํด๋น ์์ ๊ถ์ ์ด์ ํด์ผ ํฉ๋๋ค(๋ ๋ค๋ ์๋).
๊ท์น #8: API ๋ ธ์ถ ์์ญ์ IMemoryOwner ๋งค๊ฐ ๋ณ์๊ฐ ์๋ ๊ฒฝ์ฐ ํด๋น ์ธ์คํด์ค์ ์์ ๊ถ์ ํ์ฉํ๋ ๊ฒ์ ๋๋ค.
๊ท์น #9: ๋๊ธฐ P/Invoke ๋ฉ์๋๋ฅผ ๋ํํ๋ ๊ฒฝ์ฐ API๊ฐ Span๋ฅผ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๊ท์น #10: ๋น๋๊ธฐ P/Invoke ๋ฉ์๋๋ฅผ ๋ํํ๋ ๊ฒฝ์ฐ API๊ฐ Memory๋ฅผ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์. ๊ท์น์ด ์๊ฐ๋ณด๋ค ๋ง๊ตฐ์. ์ด๋ด๋๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ๋์์ฑ์ ์ธ์ด์ ์ผ๋ก ์ง์ํ๋ D Language๋ Rust ์ธ์ด๊ฐ ๋ถ๋ฝ๋ค๋ ์๊ฐ์ ํด๋ด ๋๋ค.