Весёлые приключения одной аллокации

Apr 12, 2015 22:10

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

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

Я уже говорил, что вижу в Rust достаточно большой потенциал. И ( Read more... )

code, rust, programming language, allocator, multithreading, ownership, flashmob

Leave a comment

Comments 22

thedeemon April 12 2015, 20:21:11 UTC
Отлично расписано! :)

> Мало того, у нас в наличии ситуация, когда строка аллоцируется в одном потоке, а освобождается в другом (в Си это считается страшным грехом).

И ведь не зря считается, хоть в Си может и по другой причине. При таком подходе в каждом потоке аллокатор должен быть очень thread-safe, позволять параллельную аллокацию и деаллокацию (или лочить мутексы на каждый чих). Это все хорошей скорости не очень способствует.

А в языке с GC Зинаида была бы создана быстрым bump-the-pointer способом (например) и прожила бы счастливо до конца работы данной программы. Передавался бы так же один указатель (возможно толстый, шоб длину не пересчитывать), расходов на деаллокацию могло бы быть на одну Зинаиду меньше.

Reply

swizard April 12 2015, 20:57:37 UTC
Ну, скажем, в си/с++ я редко вижу, чтобы использовалось что-то кроме штатного аллокатора, который использует libc-шный, который, в свою очередь, тред-сейфный. Сам rust использует jemalloc ( ... )

Reply

ext_1344419 April 15 2015, 09:28:33 UTC
Реализация malloc в libc сейчас основывается на ptmalloc, который мало в чем уступает jemalloc. Оба эти аллокатора используют tread local кэши объектов и per-thread арены. Если объект создается в одном потоке и разрушается в том же потоке (допустим мы используем jemalloc) - то никакой синхронизации не потребуется. Если объект создается в одном потоке и разрушается в другом, то вызов free залочит арену того потока, который создавал объект.

Reply

swizard April 15 2015, 10:47:12 UTC
> Реализация malloc в libc сейчас основывается на ptmalloc, который мало в чем уступает jemalloc

"Сейчас" -- это когда? :) Полтора года назад glibc-шный аллокатор сильно хуже был: https://github.com/rust-lang/rust/issues/6897#issuecomment-18807015

> Если объект создается в одном потоке и разрушается в другом, то вызов free залочит арену того потока, который создавал объект.

Понятно, спасибо, буду иметь в виду.

Reply


_winnie April 12 2015, 20:22:30 UTC
Возможно, я не до конца понял написаное, но умный указатель std::unique_ptr (std::auto_ptr в предыщих версиях C++) в C++ вроде обладает похожими свойствами - там нет никаких счетчиков, его можно перемещать между всякими потоками и возвращать из функций, перемещение - это копирование одного указателя (в регистры процессора, не трогая память).

Отличие - в том, что borowing не контролируется (а именно, передача обычного сишного указателя из этого умного в другую функцию), но функции в C++ обычно не сохраняют себе переданный указатель.

Второе отличие, что если используем не std::uniq_ptr, а std::string (который сам себе unique_ptr в том смысле, что есть move-конструктор), то очень легко случайно вместо перемещения использовать копирование. Тем не менее, чаще всего по умолчанию строчка текста скорее всего тоже будет протащена без всяких memcpy и alloc, и без reference counting.

Reply

swizard April 12 2015, 21:05:24 UTC
Да, всё правильно :) Наверно, если совсем грубо, то Rust + ownership -- это с++, где вообще всё (включая параметры функций и поля структур) объявляется через uniq_ptr, и нет никакого другого способа объявить переменную заданного типа. И передавать их можно только по значению.

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

Я же не случайно упомянул в тексте про масштабные проекты. В микробенчмарках, само собой, практически всегда можно догнать и обогнать Rust любым языком :)

Reply

ext_709052 April 13 2015, 12:00:06 UTC
> в с++ ты можешь вызвать функцию, передав параметром uniq_ptr, и потом совершенно свободно продолжить им пользоваться.

Не совсем так. У unique_ptr нет оператора копирования. Поэтому вот такая конструкция просто так не скомпилируется:

auto dyn_obj = make_unique< T >(...);
call_something( dyn_obj );
call_something_else( dyn_obj );

Нужно явно определять передачу владения содержимым unique_ptr:

call_something( move( dyn_obj ) );

Конечно, после этого dyn_obj все равно останется в области видимости. Но это уже не так страшно, как в свое время с auto_ptr.

Reply

thedeemon April 13 2015, 06:02:08 UTC
std::unique_ptr это двойное издевательство. Во-первых, потому что компилятор не проверяет, что мы что-то отдали и больше не владеем, разрешает дальше обращаться. Тут Rust это огромнейший шаг вперед. Во-вторых, потому что много писанины и читанины, std::unique_ptr вместо простого X*. И вообще все с ног на голову перевернуто, выглядит будто X это свойство unique_ptr, а не уникальность это свойство указателя.

Reply


antilamer April 13 2015, 05:27:14 UTC
Меня тоже здорово привлекла эта фича. Вообще, кажется, замечательный язык, C++ done right - и ownership/lifetime management правильный, и алгебраические типы есть, и эксепшнов нету, и макросы есть на всякий случай, и traits да еще с associated types, и лямбды. Читать туториал - прямо бальзам на душу. Думаю попробовать поиграться с ним на ICFPC. Жаль только, говорят, скорость компиляции паршивая пока.

Reply

thedeemon April 13 2015, 05:55:02 UTC
По ощущениям, не медленнее хаскеля компилируется.

Reply

maxim April 13 2015, 09:53:18 UTC
Говорят, что скорость компиляции не имеет значения и приводят в пример Scala и Haskell.

Reply

ext_513967 April 13 2015, 10:19:13 UTC
На самом деле конечно же имеет. И очень большое. Мы тут в мире Scala сильно страдаем из-за медленной компиляции. И fat jar'ов на 100-150 Мб.

Reply


ext_513967 April 13 2015, 10:20:18 UTC
Спасибо, очень интересный пост. Пишите больше про Rust!

Reply


dmitry_vk April 13 2015, 11:20:58 UTC
Мои впечатления от rust примерно совпадают - очень уж удачная комбинация получается.
Помимо языка, у rust уже есть замечательное коммьюнити и всякого рода инструменты и обвязки (например, чего только стоит rust-bindgen).

Reply


Leave a comment

Up