Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
if(_fooAction == null)
_fooAction = Foo;
Execute(_fooAction);
Получается, что та же самая проблема будет при использовании ConcurrentDictionary с ключём-строкой?
public bool Contains( string value ) {
return ( IndexOf(value, StringComparison.Ordinal) >=0 );
}
public Boolean StartsWith(String value) {
if ((Object)value == null) {
throw new ArgumentNullException("value");
}
Contract.EndContractBlock();
return StartsWith(value, (LegacyMode ? StringComparison.Ordinal : StringComparison.CurrentCulture));
}
public int IndexOf(String value) {
return IndexOf(value, (LegacyMode ? StringComparison.Ordinal : StringComparison.CurrentCulture));
}
public int IndexOf(String value) {
return IndexOf(value, (LegacyMode ? StringComparison.Ordinal : StringComparison.CurrentCulture));
}
Execute(() => Foo());
Execute(() => Foo());
String.Compare(strings[j], strings[length — j — 1], StringComparison.CurrentCulture) == 0Вы сейчас напугали народ длинной конструкцией, забыв сказать, что для сравнения на совпадение через Ordinal можно смело использовать ==. То есть, Ordinal нужен только в тех местах, где используются сравнение больше/меньше, таких как сортировки.
public static bool operator ==(string a, string b)
{
return string.Equals(a, b);
}
public static bool Equals(string a, string b)
{
if (a == b)
return true;
if (a == null || b == null || a.Length != b.Length)
return false;
else
return string.EqualsHelper(a, b);
}
private static unsafe bool EqualsHelper(string strA, string strB)
{
int length = strA.Length;
fixed (char* chPtr1 = &strA.m_firstChar)
fixed (char* chPtr2 = &strB.m_firstChar)
{
char* chPtr3 = chPtr1;
char* chPtr4 = chPtr2;
while (length >= 10)
{
if (*(int*) chPtr3 != *(int*) chPtr4 || *(int*) (chPtr3 + 2) != *(int*) (chPtr4 + 2) || (*(int*) (chPtr3 + 4) != *(int*) (chPtr4 + 4) || *(int*) (chPtr3 + 6) != *(int*) (chPtr4 + 6)) || *(int*) (chPtr3 + 8) != *(int*) (chPtr4 + 8))
return false;
chPtr3 += 10;
chPtr4 += 10;
length -= 10;
}
while (length > 0 && *(int*) chPtr3 == *(int*) chPtr4)
{
chPtr3 += 2;
chPtr4 += 2;
length -= 2;
}
return length <= 0;
}
}
После того, как обнаружилась эта проблема, мы стали в конструкторы всех реализаций IDictionary с ключом строкой передавать удобный StringComparer.Ordinal, что еще немного улучшило производительность.Словарём для строк используется по-умолчанию System.Collections.Generic.GenericEqualityComparer<T>, который банально вызывает Equals
// System.Collections.Generic.GenericEqualityComparer<T>
public override bool Equals(T x, T y)
{
if (x != null)
{
return y != null && x.Equals(y);
}
return y == null;
}
В библиотечных классах перечислитель сделан в виде типа-значения в давние времена, до появления обобщённых (дженерик) типов, чтобы избегать оборачивания (боксинга) в каждой итерации цикла. В наше время это неактуально.
List<T>
, который появился вместе с generic и которой как раз имеет enumerator структуру. Мне кажется вы невнимательно прочитали в чем проблема. А в целом, насчет того, что применять, а что не применять — мне кажется вы не читали кучу моих предостережений насчет того, когда стоит прибегать к этим советам.Yes, mutable structs are a bad programming practice, but in this case it’s not so bad because the foreach loop is never going to expose the raw enumerator to possible misuse by user code. Sometimes you really do want to avoid collection pressure, so making the enumerator a struct can be a small but measurable win.А свежее обсуждение немного притянуто за уши, как мне кажется. Я придерживаюсь мнения, что если ты решил делать что-то нестандартное, то будь добр — изучи матчасть. Так что я не вижу проблем в том, чтобы делать mutable structure.
Если есть возможность без вреда для внешнего кода иметь в качестве параметра конкретную коллекцию, а не интерфейс, то используйте ее, это сможет улучшить производительность foreach
Если возможности иметь в качестве параметра конкретную коллекцию нет, можно, например, использовать IList и for вместо foreach
Улучшаем производительность: полезные советы и приёмы в .NET