Обновить
45
0
Меньшиков Александр Игоревич @SharplEr

Разработчик

Отправить сообщение

Плюсую. Вообще по моему опыту люди рассуждающие о "будущем программирования" и "единственно верной парадигме", которая к нему приведёт, обычно знают мало языков и этих самых парадигм. Что приводит к попыткам переизобрести пролог: давайте опишем что мы хотим, а оно само как-то заработает.

Кафка, спарк, хадуп, игнайт, акка — основной стек на Java. Но ещё есть тарантул.
Я смотрел на результаты анализа игнайта сонаром — там почти не было реальных проблем. Он либо ругался на ерунду либо на хитрый менеджмент ресурсов, который не смог понять. Надеюсь у вас выйдет лучше)

По моему опыту люди пишут комментарии отвечающие на вопрос "что тут происходит" в сложных местах и всяких хаках, а история комитов отвечает на вопрос "зачем".

Вот что все таки в вузе есть хорошего, так это матан. Почти наверняка сам бы я заленился его учить.

Без понимания паттернов использования, ИМХО, нельзя дать общий ответ.

Я с этим полностью согласен. Видимо недостаточно ясно выразился.

Разумеется если вы упираетесь в запись, то надо брать структуру, которая оптимизирована именно на запись. Но если вы не знаете во что вы упираетесь, то разумно выбрать проверенное временем B+ дерево. А БД наперед не знает как её будет использовать пользователь.

За ссылку спасибо.
Никак. В дерево кладут значения из IgniteCache, который ведет себя как Map — а там только уникальные ключи.
Все зависит от цели. Если цель стоит измерить время запуска приложения — его и надо мерить. А если цель — это измерить производительность конкретного участка кода — надо мерить его, уже без времени запуска. Тут вариантов очень много разных и конечно не зная юзкейса делать абстрактный бенчмарк в некотором роде бессмысленно. Скажем атомарные операции стоят дороже в зависимости от того как часто они выполняются — все это надо учитывать когда вы беретесь за реальную работу.
Полное время выполнения программы это вообще нестабильная история. Для близких пар языков вроде C++ и Rust это может быть не особо существенно, но конечно Java и Rust так уже сравнивать совсем нельзя. Но и в данном случае я бы перестраховался — вроде Rust генерирует бинарники по больше чем C++ так как больше тянет из стандартной библиотеки и это может влиять на время запуска.
Так же не очень стабильно ведет себя единичный запуск. Даже для языков, где нет сложных адаптивных JIT-ов и GC, всё равно второй запуск выполнится быстрее потому, что CPU имеет некоторый элемент адаптивности внутри (предсказатель переходов и кэш). Поэтому по хорошему надо гонять бенчмарк несколько раз пока время не перестанет изменяться, и взять уже только стабильные замеры времени для ответа.
И ещё я забыл сказать: у вас в замерах не хватает погрешности. Всё таки время выполнения это случайная величина. Насколько я помню JMH для Java при подсчете погрешности считает, что время распределено нормально. Думаю это приемлемо, хотя конечно я бы взял какие-нибудь квантили — чисто на всякий случай.
Тут ещё такой момент, о которым вы тоже пишете, от которого я сам не знаю как избавиться: у языков всё таки разные стандартные библиотеки и результаты больше говорят о разницы в реализации структур данных в библиотеке, чем о чем-то другом. По хорошему надо отдельный бенчмарк сделать для этих структур в обоих языках, а потом оценить их вклад в общее время выполнения теста и как-то его вычесть наверное.
Два замечания:
1. Использование gcc для компиляции C++ в данном случае не правильно. Дело в том, что Rust использует LLVM в качестве бекенда, а gcc нет. Надо было использовать Clang, иначе твой бенчмарк сравнивает не столько Rust vs C++ сколько LLVM vs gcc.
2. В статье об этом не сказано, но в коде я кажется вижу, что вы замеряете время вызова функций руками (вижу в этом файле common/measure/src/main.rs ). В Rust в ночной сборке есть модуль для бенчмарков и надо использовать его, что бы получить более надежные результаты. Я не C++ программист, но уверен у них тоже есть своя либа для бенчмарков. Руками такое делать не стоит т.к. есть миллион граблей на которые можно наступить и получить неправильный результат.
В стандартной библиотеке много реализованных примитивов, поэтому даже для низкоуровневых задач потребности в unsafe не абсолютны. Например в четвертом примере мне требуется отправить значение в другие потоки и нет никакого смысла писать свой велосипедный Arc. И хотя есть варианты использования unsafe для производительности (например UnsafeCell), все же мне кажется главная причина его использования это наличие валидного кода для которого компилятор не может доказать валидность. Например в четвертом примере мне нужно атомарное обновление ссылки, однако доказывать корректность операций с AtomicPtr Rust не может.
Ты неверно понимаешь смысл ленивости. Ленивость это когда у тебя есть код, результаты вычисления которого может быть понадобятся, а может быть и нет, а может быть и несколько раз. Ты пакуешь такой код в Lazy и гарантируешь, что он будет вызван не более одного раза. Любой ленивый код можно переписать в нелинивую версию. Но при создании лямбды может быть не очевидно кто и как её будет использовать, и тогда ленивая версия будет проще.
Например пусть supp достает данные из БД, а таких Lazy много и их кушает оптимизационный алгоритм, который нетривиально ходит по ним асинхронно и с возвращением. Проще написать алгоритм так, будто все данные находятся в памяти, в тоже время эффективнее читать из БД только то, что нужно. И тут тебя выручит ленивость.
Статья и так получилась большой, поэтому на раздел «как нужно» не хватило. Если все сложится удачно я напишу статью-продолжение раскрывающую эту тему.
Да, вы правы. Статья о довольно низкоуровневом программировании. Веб сервисы или консольные утилиты так писать не стоит.
Ровно затем, зачем нужна ленивость. Я согласен, что в большинстве случаев она не нужна. В большинстве случаев разработчику вообще не нужно ничего по этой теме. Но мне, например, по работе приходится писать довольно много асинхронной лапши.
В статье в начале указано, что идиоматический способ другой. Сейчас выделил пункт жирным — что бы избежать недопонимания. Double check lock используют для ленивой не обязательно глобальной инициализации, поэтому sync::Once, lazy_static немного не тоже самое. Я думаю, что могут существовать ситуации, например при написании быстрых concurrency библиотек, когда подобное (не обязательно идентичное) может пригодится. В любом случае моя цель была в том, что бы начать строить мостик между человеком, который пишет concurrency код на Java, и человеком, который делает это в Rust. Подходы в языках очень разные и мне кажется не лишено смысла нащупать сперва какие-то точки соприкосновения. Тем более, что задача эта не на одну статью в любом случае.
Области не двумерные. Тут нарисовано просто абстрактное множество всех возможных входов длины n (из формул так же вытекает, что оно нормированное, но никаких предположений о его размерности не делается). А оценки времени работы на конкретном входе выделены на множестве цветом. Это не распределение вероятности, тут слово «распределение» употреблено в обычном своем значении, а не в вероятностном.
Спасибо. Исправил.
Тут действительно есть некоторое лукавство т.к. для большинства задач ввести близость решений можно по разному, что будет менять smoothed оценку. Например можно взять все возможные входы, отсортировать по времени их обработки и тогда всегда smoothed оценка будет близка к максимуму. Насколько я понимаю (но это не точно) здесь делается неявно такое предположение, что выбранная функция расстояния не будет скоррелирована с временем работы. И если у алгоритма smoothed оценка близка к худшей, значит подобрать группу плохих задач для него достаточно легко. И наоборот если она ближе к среднему, то подобрать такую группу сложно. Думаю можно даже доказать теорему, что выбранные случайным образом две функции расстояния дают в среднем не слишком разные оценки. Но формула действительно написана так, что должна существовать операция сложения на входных данных и умножения на коэффициент, кажется из этого следует линейность.

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

Информация

В рейтинге
6 546-й
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность