Комментарии 17
Вот здорово же, когда товарищи вместо евангелистических проповедей о других языках, берут и учатся у них!
Это к слову о go и планеровщике. Он действительно хорошо и, что удивительно, читаемо написан.
Интересно, можно ли в Rust управлять выравниванием данных в структурах? Потому что в такой структуре:
struct Queue {
/// Concurrently updated by many threads.
head: AtomicU32,
/// Only updated by producer thread but read by many threads.
tail: AtomicU32,
/// Masks the head / tail position value to obtain the index in the buffer.
mask: usize,
/// Stores the tasks.
buffer: Box<[MaybeUninit<Task>]>,
}
head и tail вероятнее всего будут лежать в одной кэш-линии, классический вид false cache sharing.
В пулл-реквесте тот же самый код, что и в статье. Как-то не верится, что никто из разработчиков Tokio не знаком с такими базовыми вещами из многопоточности.
Можно, надо добавить #[repr(C, align(...))]
С другой стороны, большую часть времени с этой структурой всё равно работает лишь один поток.
Компилятор Rust действительно делает переупорядочивание полей в структурах? И сможет разложить поля по разным кэш-линиям? Смахивает на городскую легенду. Например, в стандарте C++ тоже такое упоминается, но на практике это редко происходит, может быть только переупорядочивание целых секций, объявленых как public или private, иногда случается. Так что это до сих пор обязанность разработчика, думать о расположении данных при многопоточном доступе к ним:
struct Queue {
// должно начинаться с новой кэш-линии
alignas(std::hardware_destructive_interference_size) std::atomic<uint32_t> head;
// так же
alignas(std::hardware_destructive_interference_size) std::atomic<uint32_t> tail;
// так же
alignas(std::hardware_destructive_interference_size) Task buffer[mask+1];
// по идее не должно никогда меняться
const uint32_t mask;
};
А раст реально переупорядочивает play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=22dd077b561d2aefbcbe236775bd3823
Компилятор Rust действительно делает переупорядочивание полей в структурах?
Да, делает.
И сможет разложить поля по разным кэш-линиям?
Нет, не сможет. По крайней мере, в текущей версии.
Компилятор Rust действительно делает переупорядочивание полей в структурах?Да. doc.rust-lang.org/nomicon/repr-rust.html
И сможет разложить поля по разным кэш-линиям?Это можно сделать вручную, задав соответствующий атрибут align. Автоматически это делать довольно странно, потому что компилятор не знает, что на самом деле хочет программист.
Там же классический циклический буфер фиксированного размера. До mostly-lockfree mpmc растовцы еще не доросли. Короче, это false cache sharing, но сейчас разнесение по кэш-линиями даст эффект только в очень специфичных сценариях.
Точно, через пару лет этот программист напишет свою 2-ю версию многопоточной очереди. Ведь предыдущие поколения программистов были дураки, боролись с небезопасным С и страдали ерундой последние лет 20.
Если смотреть на struct Queue
, то два первых атомика будут в одной кеш-линии, которую продьюсер и консьюмер будут отбирать друг у друга. Хотя вероятно в реальном коде не так, но в 1Hippeus очереди всё равно были быстрее ;)
Мы ускорили планировщик Tokio в десять раз