عنوان:

‫جستجوی جایگزین برای دیکشنری (Dictionary) و هش‌ست (HashSet) در دات‌نت 9


نویسنده: وحید نصیری
تاریخ: ۱۴۰۳/۱۲/۲۷ ۰۸:۲۹
آدرس: www.dntips.ir
در دات‌نت 9، قابلیت جدیدی به نام «جستجوی جایگزین» (Alternate Lookup) معرفی شده‌است که عملکرد جستجو در ساختارهای داده‌ای کلیدی مانند دیکشنری (Dictionary) و هش‌ست (HashSet) را بهبود می‌بخشد. این قابلیت به ویژه زمانی مفید است که کلیدهای جستجو از نوع رشته‌ای باشند.

مشکل و راه‌حل

مشکل: در نسخه‌های قبلی دات‌نت، برای جستجوی کلیدهای رشته‌ای که به صورت «محدوده‌ی فقط خواندنی از کاراکترها» (ReadOnlySpan<char>) نمایش داده می‌شدند، نیاز به تبدیل آن‌ها به رشته‌های معمولی با استفاده از متد ToString بود. این تبدیل باعث تخصیص حافظه اضافی می‌شد که عملکرد را کاهش می‌داد.

راه‌حل: دات‌نت 9 با معرفی متد GetAlternateLookup() و ساختار AlternateLookup<T>، امکان جستجوی مستقیمی را با استفاده از ReadOnlySpan<char> را فراهم کرده است. این کار از تخصیص حافظه‌ی اضافی جلوگیری می‌کند و عملکرد را بهبود می‌بخشد. مثال:

var dic = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) {
    { "Paul", 11 },
    { "John", 22 },
    { "Jack", 33 }
};

// .NET 9 : GetAlternateLookup()
Dictionary<string, int>.AlternateLookup<ReadOnlySpan<char>> lookup = dic.GetAlternateLookup<ReadOnlySpan<char>>();

ویژگی‌های کلیدی
  • AlternateLookup<T>: یک ساختار فقط خواندنی عمومی (public readonly struct) است که به عنوان یک کلید جایگزین برای جستجو در دیکشنری (Dictionary) و هش‌ست (HashSet) عمل می‌کند. این ساختار از ویژگی «ضد محدودیت عمومی» (generic anti-constraint) سی‌شارپ 13.0 به نام «مجاز بودن ref struct» (allows ref struct) استفاده می‌کند که امکان استفاده از انواع داده‌ای مانند ReadOnlySpan<char> را فراهم می‌کند. مثال:
public readonly struct AlternateLookup<TAlternateKey>
where TAlternateKey : notnull, allows ref struct
  • IAlternateEqualityComparer<in TAlternate, T>: یک رابط (interface) است که برای مقایسه کلیدهای جایگزین با کلیدهای اصلی استفاده می‌شود. این رابط متدهایی مانند Equals() و GetHashCode() را برای مقایسه و محاسبه کد درهم‌سازی (hash code) کلیدهای جایگزین فراهم می‌کند. مثال:
namespace System.Collections.Generic {
  public interface IAlternateEqualityComparer<in TAlternate, T>
         where TAlternate : allows ref struct
         where T : allows ref struct 
   {
     T Create(TAlternate alternate);
     bool Equals(TAlternate alternate, T other);
     int GetHashCode(TAlternate alternate);
   }
}
  • SpanSplitEnumerator<T>: یک ساختار (struct) است که برای تقسیم رشته‌ها به بخش‌های کوچک‌تر با استفاده از ReadOnlySpan<char> استفاده می‌شود. این ساختار نیز از ویژگی «مجاز بودن ref struct» (allows ref struct) استفاده می‌کند. مثال:
public static SpanSplitEnumerator<T> Split<T>(
this ReadOnlySpan<T> source, T separator)

مزایای عملکرد
  • بنچمارکینگ (Benchmarking) نشان می‌دهد که استفاده از جستجوی جایگزین با ReadOnlySpan<char> در مقایسه با جستجوی معمولی با رشته، عملکرد را به طور قابل توجهی بهبود می‌بخشد و از تخصیص حافظه اضافی جلوگیری می‌کند.
  • تمام عملیات داده در جستجوی جایگزین روی پشته (stack) انجام می‌شوند که سرعت اجرا را افزایش می‌دهد.
مثال:
متد (Method)شمارش (Count)میانگین (Mean)تخصیص یافته (Allocated)
AlternateLookup_WithReadOnlySpan1009.477 میکروثانیه-
RegularLookup_WithString10011.579 میکروثانیه9600 بایت

نکات مهم
  • برای استفاده از جستجوی جایگزین با مقایسه‌کننده‌های رشته‌ای (StringComparer) مانند OrdinalIgnoreCaseComparer، این مقایسه‌کننده‌ها باید رابط IAlternateEqualityComparer<in TAlternate, T> را پیاده‌سازی کنند.
  • توسعه‌دهندگان می‌توانند پیاده‌سازی‌های سفارشی از IAlternateEqualityComparer را برای انواع داده‌ای خود ایجاد کنند.
  • متد create در IAlternateEqualityComparer برای تبدیل کلید جایگزین به کلید اصلی در هنگام تغییر کالکشن استفاده میگردد و اگر به درستی پیاده سازی نشده باشد نباید برای تغییر کالکشن استفاده شود.
مثال:

internal class PersonComparer : IEqualityComparer<Person>, IAlternateEqualityComparer<Guid, Person> {
   private PersonComparer() { }
   internal static PersonComparer Instance { get; } = new PersonComparer();

   // IAlternateEqualityComparer<Guid, Person> impl
   public Person Create(Guid id) {
   // In this sample, don't try to retrieve a Person object from its id
      throw new NotImplementedException();
   }
}

نتیجه‌گیری
قابلیت جستجوی جایگزین در دات‌نت 9، با امکان استفاده مستقیم از Span<T>، عملکرد جستجو در دیکشنری (Dictionary) و هش‌ست (HashSet) را بهبود می‌بخشد و از تخصیص حافظه اضافی جلوگیری می‌کند. این قابلیت به ویژه برای برنامه‌های کاربردی با عملکرد بالا که با رشته‌های بزرگ سروکار دارند، مفید است.



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