LINUX.ORG.RU

Rust 1.27

 


3

10

Команда разработчиков языка Rust рада представить новую версию Rust 1.27.0. Rust — системный язык программирования, ориентированный на безопасность, скорость и параллельность.

Основные изменения:

  • SIMD — наиболее значимое и ожидаемое нововведение: стабильная версия Rust обзавелась базовой поддержкой SIMD.
    Для примера использования рассмотрим следующий сниппет:
    pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) {
        for ((a, b), c) in a.iter().zip(b).zip(c) {
            *c = *a + *b;
        }
    }
    
    Здесь мы берем два слайса, складываем числа в них и помещаем результат в третий слайс. Самый простой способ, описанный выше — это проход в цикле по каждому слайсу, сложение и сохранение результата. Впрочем, это можно сделать быстрее и в LLVM может автовекторизовать такой код, подставив SIMD инструкции автоматически.

    Стабильный Rust уже давно использует возможности автовекторизации LLVM, но, к сожалению, компилятор может использовать подобные оптимизации не всегда. В Rust 1.27.0 добавлен модуль std::arch, включающий базовую поддержку использования инструкций SIMD напрямую из кода на Rust. Кроме того, добавлены соответствующие директивы условной компиляции:

    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"),
          target_feature = "avx2"))]
    fn foo() {
        #[cfg(target_arch = "x86")]
        use std::arch::x86::_mm256_add_epi64;
        #[cfg(target_arch = "x86_64")]
        use std::arch::x86_64::_mm256_add_epi64;
    
        unsafe {
            _mm256_add_epi64(...);
        }
    }
    
    В примере выше флаги cfg позволяют выбрать правильную версию функции в зависимости от целевой архитектуры во время компиляции. Также мы можем это сделать в рантайме:
    fn foo() {
        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
        {
            if is_x86_feature_detected!("avx2") {
                return unsafe { foo_avx2() };
            }
        }
    
        foo_fallback();
    }
    

    Примитивы, включенные в стандартную библиотеку обеспечивают минимальную поддержку и весьма низкоуровневы, но их включение позволяет развивать более выкокоуровневые примитывы в библиотеках. К примеру, крейт faster предоставляет удобный интерфейс, основанный на концепции итераторов.

    Без SIMD

    let lots_of_3s = (&[-123.456f32; 128][..]).iter()
        .map(|v| {
            9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0
        })
        .collect::<Vec<f32>>();
    

    С SIMD (faster)

    let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter()
        .simd_map(f32s(0.0), |v| {
            f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0)
        })
        .scalar_collect();
    

  • dyn Trait

    Изначальный синтаксис трейт-объектов в Rust — одна из тех вещей, о введении которых мы жалеем: для некоторого трейта Foo, его трейт-объект будет выглядеть так: Box<Foo>

    И если Foo является структурой, синтаксис аллокации структуры в «куче» будет выглядеть точно так же.

    Когда язык разрабатывался, казалось что сходство здесь уместно, но опыт показал, что это только путает людей.

    То же самое справедливо для случая impl SomeTrait for SomeOtherTrait, что является корректным синтаксисом, но интуитивно понимается как реализация трейта SomeTrait для всех типов, реализующих SomeOtherTrait, но на самом деле это записывается как impl<T> SomeTrait for T where T: SomeOtherTrait, в то время как первый вариант является реализацией трейта для трейт-объекта.

    Кроме того, появление impl Trait в противовес Trait ввело некую неконсистентность при обучении языку.

    Исходя из этого, в Rust 1.27 мы стабилизируем новый синтаксис dyn Trait.
    Теперь трейт-объейты выглядят так:

    // old => new
    Box<Foo> => Box<dyn Foo>
    &Foo => &dyn Foo
    &mut Foo => &mut dyn Foo
    

    То же самое применимо к другим типам указателей:
    Arc<Foo> теперь объявляется как Arc<dyn Foo>.

    Исходя из требований к обратной совместимости, мы не можем удалить старый синтаксис, но мы добавили предупреждение компилятора, призывающее обновить синтаксис для трейт-объектов. Пока что оно выключено по умолчанию.

  • #[must_use] для функций
    Наконец, атрибут #[must_use] получил новые возможности: теперь он применим к функциям.

    Раньше он использовался только на типах, таких как Result<T, E>, где возвращаемое значение должно быть использовано, но теперь возможно такое применение:

    #[must_use]
    fn double(x: i32) -> i32 {
        2 * x
    }
    
    fn main() {
        double(4); // warning: unused return value of `double` which must be used
    
        let _ = double(4); // (no warning)
    }
    

    Также этот атрибут был добавлен к некоторым функциям в стандартной библиотеке, таким как Clone::clone, Iterator::collect и ToOwned::to_owned, теперь компилятор предупредит в случае, если их результат останется неиспользованным, что поможет заметить и предотвратить случайный вызов затратных операций.

Стабилизация стандартной библиотеки

Новые возможности Cargo

В текущем релизе в Cargo включены два маленьких нововведения:

Во-первых, Cargo теперь принимает флаг --target-dir.

Во-вторых, Cargo теперь будет пытаться автоматически найти тесты, примеры и исполняемые файлы (прим. бинарные подпроекты в библиотечных крейтах) в проекте, но явная конфигурация всё же будет требоваться в некоторых случаях.

Для помощи в конфигурации мы добавили несколько ключевых слов в Cargo.toml.

Обновить Rust можно с помощью команды:

curl https://sh.rustup.rs -sSf | sh # если у вас еще не установлен rustup
rustup update stable

>>> Подробности

★★★★★

Проверено: tailgunner ()
Последнее исправление: cetjs2 (всего исправлений: 5)
Ответ на: комментарий от RazrFalcon

Связь? Я про нужность исключений. «try!» — это, конечно, не проброс сквозь стек, но ведь обеспечивает же возможность не обрабатывать ошибку на месте.

WitcherGeralt ★★
()
Ответ на: комментарий от makoven

Что оптимизируют? Атомарные операции? Лучше бы сразу с нормальным GC, рантаймом и гринтредами делали, получился бы более-менее нормальный язык, не без проблем вроде ООП конечно, но хотя-бы не то ненужно, что есть сейчас.

Nexmean
()
Ответ на: комментарий от WitcherGeralt

Анонимные функции во всех их видах я как раз очень люблю.

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

bread
()
Ответ на: комментарий от RazrFalcon

Для некоторых задач проще бросить исключение, чем городить свой enum и вручную его пробрасывать.

С failure и оператором ? это так сложно делать? Да и вообще для некоторых задач проще взять динамически типизированный Python и ...

Забавно, когда от языка просят типов, а потом - «А ЧТО, А ЗАЧЕМ ЕМУ ТИПЫ, НЕ ХОЧУ ТИПОВ, ХОЧУ КАК В ПИТОНЕ».

Nexmean
()
Ответ на: комментарий от bread

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

WitcherGeralt ★★
()
Ответ на: комментарий от Nexmean

Казалось бы, при чём тут питон?

С failure и оператором ? это так сложно делать?

Это всё равно не исключения.

Мне не нужны исключения в расте, ибо я их в принципе не люблю. Но есть задачи (быдлокод), где удобнее кидать исключения.

RazrFalcon ★★★★★
()
Ответ на: комментарий от makoven

Ловить нужно.

PS: я знаю, что в расте панику можно отловить.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Мой КО почему-то постоянно несёт бредятину не в тему.

Уточню для КО, который почему-то в очевидность как раз таки не умеет:

быдлокод

питон

Питон идеально подходит для наколеночных, либо не очень наколеночных, но при этом простых, вещей.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Да, линейные типы и синтаксис параметров времени жизни. Ничего нового в этой претензии нет. Тем не менее за все время никто адекватного решения так и не предложил.

Nexmean
()
Ответ на: комментарий от RazrFalcon

Ничего сложнее «Привет, Мир» на расте не писал. Хотел спросить, насколько муторно составлять эти enum-ы в реальных програмах?

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

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Муторность - понятие субъективное. Кода больше, чем при использовании исключений. Но это плата за статические гарантии.

Если вам нужен надёжный софт - приходится страдать.

RazrFalcon ★★★★★
()
Ответ на: комментарий от makoven

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

Собственно в функции придётся писать ? после каждого вызова функции, которая может вернуть ошибку. Определить этот enum не проблема при условии использования error-chain или failure. Будет у тебя один модуль на 20 строк кода для определения своего типа ошибки, к которому преобразуются все ошибки из сторонних либ и всё, думаю это не так много.

Nexmean
()
Ответ на: комментарий от makoven

хотел спросить, насколько муторно составлять эти enum-ы в реальных програмах?

В быдлокодинге такой подход вообще не катит. Видел стеки вызовов типичной жабской проги? А теперь представь, что мы протаскиваем ошибки вручную по всему этому стеку. Немножко жесть. Вот на го не пишут особо навороченной фигни и то там треть кода портянки с обработкой ошибок. В расте уж как плясали вокруг ошибок, придумали уже несколько способов борьбы с этой сложностью, все равно получается уныло. Зато надежно. Если у тебя глубина стека не превышает 2, то норм конечно. Только либы и писать на таких языках.

bread
()
Ответ на: комментарий от bread

Вот на го не пишут особо навороченной фигни и то там треть кода портянки с обработкой ошибок. В расте уж как плясали вокруг ошибок, придумали уже несколько способов борьбы с этой сложностью, все равно получается уныло. Зато надежно. Если у тебя глубина стека не превышает 2, то норм конечно.

А ты практикующий программист на Go или на Rust?

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

http://www.kpcb.com/file/2018-internet-trends-report
11 страница — время на мобилы растёт и потеснило совсем немного ПК.
96 страница — просмотр медиа снижается на ПК, на мобиле растёт, но по времени просмотра рекламы не изменилось у ПК ничего, при этом снижается доля ТВ, можно сделать предположение что мобилы это новый телевизор.
96 страница — ПК-рынок рекламы почти без изменений.
186 страница — намечается конец роста?
254 страница — в Китае мобилы тоже растут отдельно от ПК.

http://dq756f9pzlyr3.cloudfront.net/file/Internet Trends 2017 Report.pdf предыдущий год.

EvilFox ★★
()
Ответ на: Ultimate++ от anonymous

macOS не поддерживается.

RazrFalcon ★★★★★
()
Ответ на: комментарий от EvilFox

11 страница — время на мобилы растёт и потеснило совсем немного ПК.

Там ПК и ноуты вместе, что немного не то. Ноут тоже игрушка.

Что вы хотели доказать или опровергнуть?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Ноут тоже игрушка.

Ну я бы так не сказал. Много людей ноуты использует в работе.

Что вы хотели доказать или опровергнуть?

Я про схлопывание ПК-рынка. Об этом давно говорят, что вот-вот (прям как виндокапец), но оно почему-то не наступает. По крайней мере пока не наступило.

Тем не менее, те же майнеры в теории могут додавить ПК-игроков и те начнут мигрировать на консоли. Тогда ПК как игровая платформа во многом схлопнется, да, за исключением ММО-дрочильнь и всякого слишком взрослого для консолей.
Но если в случае MS это ещё может быть терпимо (у них есть xbox, но даже так думаю не спроста они объединили windows и xbox), то Valve уж точно едва ли захочет допустить такое и вероятно какие-то движения у неё начнутся против вредителей, к чему наверное могут ещё присоединиться мультиплатформодержатели типа EA и Ubisoft (терять нишу они тоже вряд ли захотят) и будет что-то вроде этого: https://www.youtube.com/watch?v=y28Diszaoo4

EvilFox ★★
()
Ответ на: комментарий от EvilFox

Я смотрю, в том числе, со своей колокольни: все мои знакомые и родственники давно заменили ноуты (я молчу про ПК) на телефоны и планшеты.

RazrFalcon ★★★★★
()
Ответ на: комментарий от tailgunner

А ты практикующий программист ...?

Нет конечно же. Смотри профиль.

bread
()
Последнее исправление: bread (всего исправлений: 1)

Замержили-таки async/await. Жаль. Теперь так и останется этот костыль навечно. Не стали придумывать общего решения. Очень жаль.

dave ★★★★★
()
Ответ на: комментарий от Crocodoom

Я так понял, что это преобразование AST специально для монады Future, а монад может быть бесконечно много. Они и сами в своем предложении пишут, что извините, мол, пока не осилили общее решение, что хотим как можно скорее запилить частное. Или не прав на счет AST?

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

Хотя, похоже, что async/await реализовали не через CPS-преобразование. Значит, был не прав.

dave ★★★★★
()

Xороший язык.

Вопрос публике,есть ли годный JIT компилятор написаный на расте? Мучу свой недоЯП и интерпретатор чрез чур медленный

playX ★★
()
Ответ на: комментарий от playX

Вопрос публике,есть ли годный JIT компилятор написаный на расте?

Cretonne - JIT-компилятор WebAssembly: https://github.com/cretonne/cretonne

Осталось написать транслятор в WebAssembly вместо интерпретатора :)

tailgunner ★★★★★
()

Как у сообщества, сложившегося вокруг языка Rust, обстоят дела с библиотеками для численных методов? Видел пару самопальных библиотек для blas: одна wrapper для фортрановской, что уже неплохо; вторая не документированная - не нашёл описания.

Есть ли аналоги Eigen, Armadillo, Blitz++, Numpy (видел контейнер ndarray для rust), Odeint, SciPy? Есть ли поддержка MPI?

grem ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.