Как стать автором
Обновить

Комментарии 13

Макс, спасибо за цикл статей. Забавно, что это стандартная библиотека Kotlin и казалось бы все должно быть заоптимизировано...

Да, удивительное рядом). Меня больше поразило, что Джек Вортон обнаружил это еще в 2019 году и они так и не поправили это для связки Enum + When

Я знаю что у ProGuard/R8 есть замена простых Enum на Int, но вот не знал что это не работает со switch

Смотрю я на все эти ухищрения, для того, чтобы итераторы нормально работали и меня охватывает тоска. Вот поддерживала бы jvm генераторы или разработчики kotlin реализовали бы их сами на уровне генерации байткода(не знаю, насколько это реализуемо, но компилятор C# именно так и делает), столько лишней работы можно было бы избежать. Например, реализация flatten стала бы настолько простой, что даже как-то смешно.

fun <T> Iterable<Iterable<T>>.flatten(): Iterable<T>{
    for(iterable in this){
        for(item in iterable){
            yield item
        }
    }
}

И производительность при этом проседать не должна, так как по сути при генерации получился бы такой же код, как и в ручной реализации, а при наличии поддержки yield со стороны JVM, ещё бы и прибавку в скорости могли получить.

Ты не совсем верно уловил суть sequences. Это ленивая конструкция, а в твоем примере ты просто перебираешь все элементы подряд.
Код твоего цикла for на самом деле в Java выглядит вот так и он безусловно переберет все элементы за раз.

while (iterable.hasItem()) { iterable.next() }

А в случае sequences вызов каждой итерации по циклу запускается внешним кодом. Сам цикл ленивый и он не перебирает элементы. И все это обернуто в удобные конструкции так, что ты даже не замечаешь, что работаешь теперь не с коллекциями, а с последовательностями.

В случае преобразования коллекций использование sequences дает некоторый выигрыш по скорости. Но основная задача sequences не в этом, а в возможности работать с огромными структурами данных, не загружая их целиком в память.

Например ты можешь через sequences лениво читать файл в 20ГБ по одной строке, при этом снаружи этот код будет выглядеть также, как будто ты работаешь с обычной коллекцией и загрузил весь файл в память. При этом в памяти у тебя всегда будет только одна строка из огромного файла.

csfFile.useLines
    .drop(1)
    .map { line -> line.toRecord() }
    .filter { record -> record.hasAccount }
    .forEach { record -> repository.writeRecord(record) }

тогда сорри, значит это я неправильно понял) Уже очень давно не писал на C#
Интересная концепция, посмотрю на досуге ее.

На самом деле в шарпах тоже полно магии. Линку изнутри сделан на кастомных стейтмашинах, которые мутируют друг в друга, если возможно.

Вот, например, WhereSelectArrayIterator.

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

Супер, круто сделал!

Единственное при сравнении алгоритмов также следует учитывать разницу в используемой памяти

Согласен, на самом деле я смотрел ее, но по инстансам они равны. В коллекциях на каждое преобразование создается инстанс коллекции, а в сиквенсах инстанс декоратора.

Выигрыш по памяти для сиквенсов очевиден, так как в коллекциях постоянно выделяется и освобождается массив + копирование элементов. И именно за счет исключения этого сиквенсы и выигрывают.

Но вы правы, я не копал глубоко эту тему. Просто поверхностно посмотрел профайлером.

Спасибо за статью! Печально, что на Хабре теперь приходится такие статьи прям выискивать среди «шума».

Спасибо за приятный отзыв. Он особенно приятен, потому что тоже испытываю подобные ощущения)

Количество шума как то резко выросло в последнее время.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации