tgoop.com/csharp_gepard/137
Last Update:
ByReferenceStringComparer #скорость
Недавно появилась задача быстро искать цифры по словарю. Ключ - строки, которые приходят извне, но которые всегда из определённого списка. Значение - число. В исходном коде на каждый запрос происходил поход в БД, создавался словарик, после этого по нему десятки (если не сотни) раз осуществлялся поиск по ключу.
Оптимизация первая. Ходить в БД за этими цифрами, очевидно, долго, да и данные обновляются редко, поэтому первая оптимизация - кэш через словарик на микросервисе. Это дало 50% прироста производительности. Неплохо. В принципе, заказчик уже был доволен, но мне хотелось большего.
Оптимизация вторая. Как я уже заметил, словарик, по ходу запроса, используется очень-очень часто. Это было отлично заметно в профайлере. Причём основное время тратилось на получение хэша и сравнение строк.
Я прогнал все входящие строки и все ключи из БД через штуку а-ля string.Intern
. Таким образом я получил строки, идентичные по ссылке, что, кажется, должно облегчить сравнение строк. Я надеялся, что FrozenDictionary это заметит и применит какие-то оптимизации. Увы, нет. Тем не менее, я получил небольшой прирост производительности, когда перешёл на Frozen.
Однако, сравнение через ссылку не давало мне покоя. Я вспомнил, что некто Евгений рассказывал, что Serilog не эффективно использует кэш темплейтов для получения подготовленного сообщения. Мол, в качестве IEqualityComparer<string>
для ключа словаря можно было бы сравнивать строки по ссылке, а хэш получать из заголовка инстанса строки. В принципе, для этого сценария у меня уже всё было готово, и я начал создавать Frozen с указанием вот этого компарера:
class ByRefStringComparer : IEqualityComparer<string>
{
public bool Equals(string? x, string? y)
{
return ReferenceEquals(x, y);
}
public int GetHashCode(string obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
Не скажу, что последняя оптимизация внесла весомый вклад, но, тем не менее, она была достаточно полезная. Во всяком случае ещё 3-5% скорости могут помочь в ситуации высокой нагрузки.
Бенчмарк в комментариях.
Замечу, что подобный подход может помочь только (!) в случаях, когда набор строк ограничен (например, список названий областей страны) и по ним часто и много ищут. То есть не нужно использовать подход, если у вас разные строки, либо строка в алгоритме используется всего один раз. Пропуская все строки через аналог
string.Intern
вы просто переложите поиск строки из одного места в другое.BY C# Heppard

Share with your friend now:
tgoop.com/csharp_gepard/137