Pull to refresh
17
0
Сергей Семёнов @tyrotoxin

User

Send message
Имеется в виду округление в большую сторону по абсолютному значению. А так, округление всегда в меньшую сторону.
int v1 = -11;
(v1 >> 1) = -6;
int v2 = 11;
(v2 >> 1) = 5;
Abs(v1) > Abs(v2)
Работает, только округление происходит в большую сторону, а не в меньшую (как с положительными числами).
Сдвига вправо есть два — знаковый и беззнаконвый. Для отрицательных чисел знаковый сдвиг сохраняет старший бит и дублирует его во младшие, что даёт желаемый результат.
В таких языках как Java, есть соответствующие операторы ">>" и ">>>", а в C# знаковый сдвиг выполняется для типов данных, которые могут быть отрицательны (short, int, long), а беззнаковый — для остальных (byte, ushort, uint, ulong).
Да вот же:
Начните с … 1. Хороший алгоритм.

Нет, начинать надо с того, что определить, где именно у вас боттлнек (и есть ли он вообще).

В моём понимании это значит: «Давайте сделаем в лоб не задумываясь, а потом найдём проблему и придумаем для неё алгоритм решения» :D
Вот началось с этого коментария. Из всего моего комерческого опыта, на C# как раз так почти никто не пишет :)
Я бы вам плюс поставил, но карма у меня маленькая — не взлюбила меня публика :)
Забавно, что кто-то следит за нитью :)
Здесь я с вами согласен — я останавливаюсь комментировать, я не вижу смысла дальнейшего обсуждения, т.к. трачу своё время непонятно на что, когда его можно вложить в изучение новой предметной области :D
Спасибо за сигнал!
Потому что основные бизнес-алгоритмы, насколько я понимаю, уже были разработаны.

мы именно всё переделали с чистого листа, используя накопленный опыт.

Вопрос в том, получили ли вы соответствующий прирост прибыли, и не выгоднее ли было вложить эти ресурсы в разработку новой функциональности.

Это действительно очень интересно, но не по теме статьи :)
Я уже не помню, но первая версия заняла у команды где-то 15000-17000 человеко-часов — тогда нам приходилось проходить долгий путь изучая много деталей (сколько из них ушло на оптимизацию — тут никто не скажет).
Мы потратили в почти 10 раз меньше времени чтобы это всё переделать с чистого листа и довести до предела. Как вы оцените такие цифры? Неужели всё так плохо и стоит задуматься?
Здесь согласен, этот момент не освещён. Такие замечания действительно полезны, поэтому я их обязательно учту. На самом деле я пишу историю про вторую версию приложения. Первая версия со штатными оптимизациями была на уровне конкурентного решения, где-то чуточку выигрывая. Это был предел, которые мы могли позволить стандартными средствами.

А вот вторая версия была начата с чистого листа, где умение построить понятную программисту архитектуру и совместить её с суровыми оптимизациями — это исскуство. Поэтому не стоит думать, что цена такого подхода слишком большая. Код там — не «манная каша», а хорошо продуманное до мелочей архитектурное решение, которое даже лучше первого (просто код некоторых методов сложнее).

Стоимость разработки — около 1700 человеко-часов. Поверьте, это совсем ничего для такого серъёзного продукта. Всё зависит от мастерства разработчиков, кто-то может потратить в 10 раз больше времени и близко не достичь такого же результата.

А ошибок ли? Лучше разобраться на реальных примерах, прежде чем утверждать. Ваше право поставить под сомнение — это нормально, но сразу заявлять о некорректности я бы не стал.
Я привёл пример в «Специальном дополнении», но не намерен этого делать по каждому пункту — статья итак слишком большая получилась, да и книгу мне писать не хочется :)
И поймите меня правильно, что я нигде не спорю и не утверждаю что подход «сделать, найти bottleneck, оптимизировать» чем-то плох и нигде не спорю о разумности отимизаций штатными средствами. Статья ориентирована совершенно на другую тематику, и я честно предупреждаю во что может превратится код после таких оптимизаций.
Пожалуйста, прочтите внимательно. Я пишу вначале статьи:
для достижения максимальной производительности приложений, которые этого требуют

Разбор:
• «для производительности приложений» — статья на эту тему
• «достижения » — будет описано как это сделать
• «максимальной» — это значит «предел», дальше некуда
• «которые этого требуют» — слово «которые» относится к слову «приложений» и уточняет подмножество всего множества приложений; «этого» относится к «максимальной производительности»
Т.е. я даю советы только для тех приложений, которые требуют достижение предела в возможной прозводительности. Статья так и называется «Предельная производительность», и не претендует на звание «Guideline для оптимизации всех приложений».
Поэтому в рамках такого подмножества я считаю правомерным давать свои советы. Читатели, которые невнимательно прочли, или не поняли в чём-то суть — это уже не моя ответственность. Любой человек может что-то невнимательно прочитать в том же MSDN и пойти писать «китайский» код (ничего не имею против китайцев, просто такое выражение).
Я очень люблю C# и .NET (особенно WPF по сравнению с WinForms) — классные штуки, которые позволяют быстро и эффективно создавать приложения с минимумом затрат.
После многолетней работы с высокопроизводительными приложениями на C++, assembler + SIMD, CUDA и пр. мне интересно было «А что если применить накопленный опыт в .NET и выжать из него по-максимуму?». Причём проект как раз попался требующий производительности. Эксперимент удался, и принёс отличные плоды, поэтому захотелось написать статью и поделится таким необычным опытом :)
Вы так говорите, как будто я пропагандирую такой способ разработки. Я нигде в статье не даю советы как нужно разрабатывать приложения, а вы мне пытаетесь рассказать инное.
Вы понимаете что проект, на котором был поставлен эксперимент такой разработки, просто демонстрирует чего можно добиться? И как это отличается от стандартного подхода «сделать, найти bottleneck, оптимизировать», который представлен конкурентным решением? Почему вы отвергаете такого рода эксперименты и рассказваете мне как «надо» делать?
Вы хотели бы увидеть очередную статью «Как я воспользовался профайлером..»? Я предлагаю другой взгляд на вещи.
Предвижу совет использовать SSD или наушники :)

Троллей хватает, так что предвидение вполне реально :)

Я знаю одну ISV компанию, самую крупную в Европе в определенной сфере, которая отказалась от Java, и переписали весь код на С++. Более того они реализовали свой движок распределённой базы данных, которая заточена под конкретную цель. И много чего ещё сделали, чтобы их система могла стоять на самых дешёвых серверах под Linux. Итог — один из самых лучших и известных продуктов, которым пользуются сотни миллионов пользователей по всему миру.
Это на тему советов «серверу добавить памяти, поставить SSD, добавить узлы в датацентр» :)
Дорогой lair, я вам всё уже объяснил. Это всего лишь одна функция из сотен, которые используются для синтаксического разбора. Если весь парсер хорошенько оптимизировать, то разница может измерятся в десятках секунд.
Что выпытаетесь доказать?
— Что оптимизация не работает? Она работает, вы согласитесь.
— Что так писать нельзя? Можно — нет сборника законов или «библии», которая говорит как можно писать код а как нельзя.
— Что так писать неразумно? Об этом никто и не спорит, я постоянно в статье твержу что применять такую оптимизацию использовать по необходимости, и что она может привести к «вонючему» сильно связанному коду, который сложно поддерживать, развивать.
Спасбо вам — хоть один человек сказал вразумительные слова :)
Опять же, это не guidline, а просто пример как можно выжать помаксимуму из .NET. Я сам почти никогда так не пишу, пока это действительно не востребованно.
" дотнет в общем и целом — зло" — тут я предвижу много гнилых помидоров, летящих в вашу сторону :) Эти споры — как религия, никогда ничем хорошим не заканчиваются :)
Имелось в виду при использовании HashSet<T> без своего IEqualityComparer. А в GenericEqualityComparer как раз и вызываются стандартные методы Equals и GetHashCode.

Вы — самый настоящий тролль. В вашем коментарии я вижу всего один умысел — поумничать. Придраться можно абсолютно бесконечно к любой мелочи, чем собственно вы и занимаетесь. Вы бы ещё добавили, что Object.ReferenceEquals может вернуть true; что хэш коды на самом деле не сравниваются, что остатки от их деления являются индексами в массиве; что пример кода неправильный, там «if» не в том месте, и что bucketIndex может быть отрицательным; и т.д. и пр.

Прочитайте раздел «Специальное дополнение», которое я добавил в конец статьи. Может тогда вы станете добрее… :)
Если искать по строке, то верно что будет расчитан hash code, однако при совпадении этого кода переданная строка будет сравниваться побайтого с той, которая лежит в HashSet (потому что Object.ReferenceEquals вернёт false).
Если искать сразу по hash code, то HashSet для расчёта hash code ключа типа int будет использовать само значени ключа типа int, и сравнивать строки не нужно — будут сравниваться значения типа int. Т.е. что-то типа такого:
int key = 12345; // pre-computed hash code for a string

bool Contains<T>(T key) { // where "T" is "int"
  int hashCode = key; // get hash code for "T" type, when it's "int"
  int bucketIndex = hashCode % bucketCount;
  int itemIndex = buckets[bucketIndex];
@loop:
  Item item = itemArray[itemIndex];
  if (item.Key == key) // Call operator '==' for 'T' type.
    return true;
  itemIndex = item.NextItemIndex;
  if (itemIndex >= 0)
    goto loop;
  return false;
}
Небольшой тест в Visual Studio под .NET Framework 4.5 и x64 показал, что объект String состоит из:
• 4-byte SyncBlock
• 8-byte type descriptor (или 4 byte для 32-bit)
• An int32 field — длина строки
• символы по 2 байта, без null terminator

Information

Rating
Does not participate
Registered
Activity