عنوان:

‫طراحی یک دیکشنری کارآمد برای ردیابی آدرس IP با استفاده از AlternateLookup و IAlternateEqualityComparer دات‌نت 9


نویسنده: وحید نصیری
تاریخ: ۱۴۰۳/۱۲/۲۷ ۰۸:۵۹
آدرس: www.dntips.ir
این مقاله به معرفی و نمایش پیشرفت‌های مجموعه‌ها در NET 9. و C# 13 برای کاهش تخصیص حافظه می‌پردازد. به طور خاص، استفاده از یک IAlternateEqualityComparer سفارشی و AlternateLookup را در یک Dictionary (دیکشنری) برای ردیابی کارآمد اطلاعات آدرس IP، با کلیدهای بایت‌های آدرس IP، نشان‌ می‌دهد.

مفاهیم کلیدی:
  • مورد استفاده: ردیابی تعداد درخواست‌ها از آدرس‌های IP غیر GitHub با استفاده از Dictionary که با بایت‌های آدرس IP، کلید گذاری شده‌است.
  • اولویت دادن به عملکرد و کارایی حافظه.
  • تعریف دیکشنری: از Dictionary<ReadOnlyMemory<byte>, string> استفاده می‌شود.
  • ReadOnlyMemory<byte> به عنوان کلید، با یک مقایسه کننده سفارشی (ReadOnlyMemoryComparer).
  • مقدار، در این مثال، یک رشته است.
  • مدیریت آدرس IP:Span<byte> برای نگهداری بایت‌های آدرس IP استفاده می شود، از تخصیص‌های غیر ضروری جلوگیری می‌کند.
    • stackalloc یک بافر بایت را در پشته تخصیص می‌دهد.
    • IPAddress.TryWriteBytes بافر را پر می‌کند.

var ipAddress = IPAddress.Parse("172.100.50.50");
var size = ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16;
 
Span<byte> key = stackalloc byte[size];
 
if (!ipAddress.TryWriteBytes(key, out var bytesWritten))
{
    // Should never happen
}
 
key = key[..bytesWritten];

IAlternateEqualityComparer (مقایسه کننده برابری جایگزین): امکان استفاده از یک نوع جایگزین (ReadOnlySpan<byte>) برای جستجوی کلید را فراهم می‌کند.
  • ReadOnlyMemoryComparer هر دو IEqualityComparer<ReadOnlyMemory<byte>> و IAlternateEqualityComparer<ReadOnlySpan<byte>, ReadOnlyMemory<byte>> را پیاده سازی می‌کند.
  • شامل متدهای Equals، GetHashCode و Create است.
  • متد create هنگام اضافه کردن یک مورد جدید به فرهنگ لغت، برای تبدیل بازه به ReadOnlyMemory استفاده می‌شود.
internal sealed class ReadOnlyMemoryComparer : IEqualityComparer<ReadOnlyMemory<byte>>, 
    IAlternateEqualityComparer<ReadOnlySpan<byte>, ReadOnlyMemory<byte>>
{
    public static IEqualityComparer<ReadOnlyMemory<byte>> Default { get; } = new ReadOnlyMemoryComparer();
 
    public ReadOnlyMemory<byte> Create(ReadOnlySpan<byte> alternate) => 
        alternate.ToArray();
 
    public bool Equals(ReadOnlySpan<byte> alternate, ReadOnlyMemory<byte> other) =>
        alternate.SequenceEqual(other.Span);
 
    public bool Equals(ReadOnlyMemory<byte> x, ReadOnlyMemory<byte> y) => 
        x.Span.SequenceEqual(y.Span);
 
    public int GetHashCode(ReadOnlySpan<byte> alternate)
    {
        HashCode hc = default;
        hc.AddBytes(alternate);
        return hc.ToHashCode();
    }
 
    public int GetHashCode(ReadOnlyMemory<byte> obj) => GetHashCode(obj.Span);
}

AlternateLookup (جستجوی جایگزین):
  • dictionary.GetAlternateLookup<ReadOnlySpan<byte>>() متدهایی را برای عملکرد در دیکشنری با استفاده از ReadOnlySpan<byte> فراهم می‌کند.
  • امکان جستجوی موارد را با حافظه تخصیص یافته در پشته فراهم می‌کند.
    • alternateLookup[buffer] = "Hello, world!"; یک مورد را اضافه می‌کند.
    • alternateLookup.ContainsKey(buffer); وجود را بررسی می‌کند.
var alternateLookup = dictionary.GetAlternateLookup<ReadOnlySpan<byte>>();
alternateLookup[buffer] = "Hello, world!";
var exists = alternateLookup.ContainsKey(buffer); //true

مزایا:
  • از تخصیص‌های میانی، در طول جستجوی کلید جلوگیری می‌کند.
  • مقایسه‌های بالقوه سریعتر در مقایسه با استفاده مستقیم از IPAddress به عنوان کلید.
  • برای سناریوهایی که Span<T> می‌تواند مقادیر کلیدی را بدون تخصیص پشته تجزیه یا تولید کند، مفید است.

مثال متعارف:
  • دیکشنری‌های کلید گذاری شده رشته‌ای اکنون می‌توانند با تجزیه Span<char> برای جستجو، از تخصیص رشته جلوگیری کنند.


مشاهده مطلب اصلی