• Как правильно принимать данные в потоках?

    bingo347
    @bingo347
    Crazy on performance...
    Arc нужно клонировать до move в замыкание, которое запускается на потоке. Если данные используются только на чтение, то этого будет достаточно, если данные будут меняться из нескольких потоков, то следует дополнительно обернуть их в Mutex/RwLock (или из std::sync или из библиотеки parking_lot).
    use std::sync::Arc;
    
    fn main() {
        let data = Arc::new(vec![1, 2, 3]);
    
        let thread_1 = std::thread::spawn({
            let data = Arc::clone(&data);
            move || {
                println!("Thread 1 data: {:?}", data);
            }
        });
    
        let thread_2 = std::thread::spawn({
            let data = Arc::clone(&data);
            move || {
                println!("Thread 2 data: {:?}", data);
            }
        });
    
        thread_1.join().unwrap();
        thread_2.join().unwrap();
    }

    Передавать так можно хоть вектор, хоть свою структуру, главное чтоб у типа был трейт Send и лайфтайм 'static (все владеющие типы имеют такой лайфтайм).
    Так как передаем мы по сути Arc, то Send должен быть у него, а он будет для любого содержимого реализующего Sync.

    Я обернул создание отдельного потока в функцию и так передавал в поток данные. Удобно, что такую функцию могу вынести в отдельный файл-модуль. Но не смог такое сделать динамически в цикле для группы потоков. Хочу подойти к варианту, когда поток, который закончил выполнение своего кода (раньше других), можно опять запустить из main и передать ему новую задачу (новые данные), - структуру данных, которую привёл в основном вопросе.
    Если правильно понял, то Вам нужен thread pool. Можно использовать из библиотеки rayon: https://docs.rs/rayon/1.7.0/rayon/struct.ThreadPoo...
    Но если хочется повелосипедить, можно нечто такое сделать:
    use std::{
        sync::{
            mpsc::{self, Sender},
            Arc, Mutex,
        },
        thread::{self, JoinHandle},
    };
    
    type Task = Box<dyn FnOnce() + Send + 'static>;
    
    pub struct ThreadPool {
        handles: Vec<JoinHandle<()>>,
        task_sender: Sender<Task>,
    }
    
    impl ThreadPool {
        pub fn new() -> Self {
            let threads_count = thread::available_parallelism()
                .map(|n| n.get())
                .unwrap_or(2);
            let (task_sender, task_receiver) = mpsc::channel::<Task>();
            let task_receiver = Arc::new(Mutex::new(task_receiver));
            let mut handles = Vec::with_capacity(threads_count);
            for _ in 0..threads_count {
                let task_receiver = Arc::clone(&task_receiver);
                handles.push(thread::spawn(move || loop {
                    let task_receiver = task_receiver.lock().unwrap_or_else(|e| e.into_inner());
                    let Ok(task) = task_receiver.recv() else {
                        return;
                    };
                    drop(task_receiver);
                    task();
                }));
            }
            Self {
                handles,
                task_sender,
            }
        }
    
        pub fn spawn_task<F: FnOnce() + Send + 'static>(&self, f: F) {
            self.task_sender.send(Box::new(f)).expect("All threads ended");
        }
    
        pub fn join(self) -> thread::Result<()> {
            drop(self.task_sender);
            for handle in self.handles {
                handle.join()?;
            }
            Ok(())
        }
    }
    
    #[test]
    fn thread_pool() {
        let pool = ThreadPool::new();
        for i in 0..500 {
            pool.spawn_task(move || {
                println!("Task {} working on thread {:?}", i, thread::current().id());
            });
        }
        pool.join().unwrap();
    }
    Ответ написан
    3 комментария
  • Как получить путь к испольняющемуся файлу rust?

    @deliro
    use std::env::current_exe;
    
    fn main() {
        let x = current_exe();
        println!("{x:?}")
    }
    Ответ написан
    1 комментарий
  • Чем заменить TeamViewer - чтобы было просто и понятно обычному пользователю, который компьютер только умеет включать и выключать?

    @flexpc
    AnyDesk, хорошая программа, есть на все платформы, если ты этому пользователю ее установишь и закинешь в автозагрузку, то сможешь в любой момент подключаться.
    Ответ написан
    1 комментарий
  • Что значит -> в Rust?

    ozkriff
    @ozkriff
    Rust э̶н̶т̶у̶з̶и̶а̶с̶т сектант, хобби игродел
    растбук: "Функции возвращающие значения" - просто часть ситнаксиса ржавых функций, которая используется когда нужно явно обозначить возвращаемый тип.
    Ответ написан
    Комментировать
  • В чем причина утечки памяти в программе на rust?

    @GeraZlo Автор вопроса
    Устранил утечку переписав большую страшную функцию, в замыкании на две маленькие, вынеся всю логику за пределы замыкания.

    Было:
    impl UserRssItemsFilter for FilterByLastRequestData {
        fn filter(&self, user: i64, rep: &String, item: &RssItem) -> bool {
            let key = format!("{} {}", user, rep);
            let r = self.last_request_cache.write(|db| {
                let last_request: DateTime<Utc> = if let Some(last_request_str) = db.get(&key) {
                    DateTime::parse_from_rfc2822(&last_request_str).unwrap().into()
                } else {
                    Utc::now() - Duration::days(2)
                };
                if last_request < item.created_date {
                    db.insert(key, item.created_date.to_rfc2822());
                    true
                } else {
                    false
                }
            }).unwrap();
            self.last_request_cache.save().unwrap();
            r
        }
    }


    Стало:
    impl UserRssItemsFilter for FilterByLastRequestData {
        fn filter(&self, user: i64, rep: &String, item: &RssItem) -> bool {
            let key = format!("{} {}", user, rep);
            let last_request = match  self.last_request_cache.read(|db| {
                match db.get(&key) {
                    Some(v) => Some(DateTime::parse_from_rfc2822(v).unwrap().into()),
                    None => None
                }
            }).unwrap() {
                Some(v) => v,
                None => Utc::now() - Duration::days(2)
            };
    
            if last_request < item.created_date {
                self.last_request_cache.write(|db| {
                    db.insert(key, item.created_date.to_rfc2822());
                }).unwrap();
                self.last_request_cache.save().unwrap();
                true
            } else {
                false
            }
        }
    }
    Ответ написан
    Комментировать
  • Какие игры написанные на Rust посоветуете?

    ozkriff
    @ozkriff
    Rust э̶н̶т̶у̶з̶и̶а̶с̶т сектант, хобби игродел
    На расте не так уж и много игр пока написано, тем более если рассматривать только опенсорсные. В первую очередь в голову приходят https://veloren.net и https://github.com/a-b-street/abstreet - эти проекты весьма глубокие и интересные чисто на пользовательском уровне.

    Еще можно посмотреть на
    https://github.com/amethyst/theta-wave
    https://github.com/mrDIMAS/StationIapetus
    https://github.com/ozkriff/zemeroth
    https://github.com/heroiclabs/fishgame-macroquad
    https://github.com/Grokmoo/sulis

    Если что, мы стараемся основные ржаво-игровые проекты в https://arewegameyet.rs#games каталог добавлять - можно его покопать, вроде там еще чего-то интересное открытое должно быть.

    чтоб на Raspberry Pi4 потянули.

    Какие из проектов заведутся на малине - совершенно не представляю, к сожалению.
    Ответ написан
    Комментировать
  • Хайп вокруг ЯП Rust и C?

    bingo347
    @bingo347
    Crazy on performance...
    Насколько критичной проблемой для программиста является ручное управление памятью, которое называют недостатком языка Си?
    Неосвобожденная память (утечка памяти) - это самое безобидное, что может произойти.
    - Сделать free дважды - это UB
    - Забыли проверить результат malloc/calloc/realloc на не NULL, разыменовали - UB
    - Почитали память, в которую ни разу не писали - UB
    - Разыменовали указатель после free - UB
    - Гонка данных - UB
    - ...и еще дофига всего, от чего в лучшем случае программа просто будет работать неправильно, например спалит Ваш пароль, или переведет Ваши деньги на другой счет 10 раз.

    Новый язык программирования Раст, как заявляют, лишен этого недостатка

    Система типов Rust гарантирует лишь одно - в safe коде не будет UB. Утечка памяти, кстати, не является UB, поэтому память вполне себе можно утечь в safe коде, помимо циклических счетчиков ссылок std дает немало возможностей сделать это напрямую:
    https://doc.rust-lang.org/beta/std/mem/fn.forget.html
    https://doc.rust-lang.org/beta/std/mem/struct.Manu...
    https://doc.rust-lang.org/beta/std/boxed/struct.Bo...
    https://doc.rust-lang.org/beta/std/vec/struct.Vec....

    но разве число ошибок в программе зависит именно от наличия или отсутствия ручного управления памятью
    В Rust ручное управление памятью, как и в C и в C++, просто есть культура, что если некая структура аллоцировала память, то она ее освободит. Всякие Vec, Box и т.д. делают это в Drop. В C++ многие повседневные типы так же освобождают в деструкторе память, которую они выделили. Однако в Rust есть разделение на safe и unsafe код и для прикладного программирования safe возможностей более чем достаточно. В C++ же весь код unsafe.

    разве общее число ошибок не перераспределяется на другие недостатки программы
    Нет, не перераспределяется. Хорошая система типов действительно может избавить от многих ошибок, что в целом сделает ПО более надежным. Но надо понимать, что от всех ошибок не избавит ни что. Банальная дискоммуникация с заказчиком порождает огромное число багов.
    Но в Rust очень быстро привыкаешь к такому замечательному подходу в разработке, как Type Driven Development, который позволяет предупредить многие ошибки еще до написания кода. После Rust я стал применять этот подход и в других ЯП, и он работает очень хорошо, даже там, где типизация не такая строгая.

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

    P.S. Вот интересная статья про Rust к прочтению: https://steveklabnik.com/writing/a-sad-day-for-rust
    И к чему она привела: https://github.com/fafhrd91/actix-web-postmortem
    Ответ написан
    4 комментария
  • Хайп вокруг ЯП Rust и C?

    vabka
    @vabka
    Токсичный шарпист
    По порядку:
    Насколько критичной проблемой для программиста является ручное управление памятью, которое называют недостатком языка Си?

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

    (Дальше какое-то ужасно длинное предложение, которое я разбил на части)
    Новый язык программирования Раст, как заявляют, лишен этого недостатка

    Да
    разве общее число ошибок не перераспределяется на другие недостатки

    1. Самые сложные в исправлении ошибки - кривое управление памятью и многопоточность, обе их Rust Решает
    2. Нет, ошибки не перераспределяются, это же не тараканы.
    являются ли ошибки с памятью ошибками программиста

    Если управление памятью ручное, то это ошибки, которые допустил разработчик.
    Если управление памятью автоматическое (хоть через GC, хоть через Borrow checker), то это ошибка компилятора/рантайма/языка.

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

    Не обязательно.

    В целом вопрос очень абстрактный и является скорее поводом для дискуссий. Попробуйте дать более конкретный пример, где ошибка управления памятью превращается в какую-то другую ошибку.
    Ответ написан
    Комментировать
  • Нету config файла в .cargo (macOS)?

    ozkriff
    @ozkriff
    Rust э̶н̶т̶у̶з̶и̶а̶с̶т сектант, хобби игродел
    Его по умолчанию и не должно быть - создавай сам в нужном скоупе, если что-то в него надо прописать.
    Ответ написан
    Комментировать
  • Можно ли читать устаревшее издание книги Таненбаума "Архитектура компьютера"?

    firedragon
    @firedragon
    Не джун-мидл-сеньор, а трус-балбес-бывалый.
    Вас не смущает что Windows и Линукс сделаны на идеях 60х ?
    И еще долго работать будут, хотя все порываются ядро переписать на другом языке, но нет не взлетает.
    Ответ написан
    2 комментария
  • Какие задачи решают на Rust, а какие на Golang?

    bingo347
    @bingo347
    Crazy on performance...
    Какие задачи решают на Rust
    любые. Rust - язык общего назначения, применимый к большинству возможных задач. Rust достаточно высокоуровневый для написания на нем прикладного ПО и компилируется в достаточно эффективный машинный код, для применения в ядрах ОС, драйверах или embedded разработке. Так же Rust на сегодня имеет самый маленький размер при компиляции в wasm, что критично для использования в web. Я честно не знаю такой сферы, к которой бы не подошел Rust.
    Единственной проблемой в применимости Rust я вижу недостаточную его распиаренность в РФ, что часто бывает самым важным критерием для "манагеров" и прочих людей принимающих решения о используемом стеке.
    а какие на Golang
    Golang тоже язык общего назначения, но имеющий ряд ограничений:
    - Крайне тяжелый рантайм не дает возможность использовать его в wasm, embedded или компонентах ядра.
    - Необходимость в сборке мусора опять таки ограничивает разработку для embedded или компонентов ядра.
    - Отказ от llvm в качестве бэкенда компилятора ограничивает число целевых платформ.
    Можно один заменить другим?
    Rust спокойно заменяет Golang в любой возможной на последнем задаче, наоборот же иногда имеем ряд ограничений.

    Вместо P.S.:
    Golang скорее всего окажется более быстрым для прототипирования и быстрого старта. Однако отсутствие полиморфизма в любом виде (утиная типизация не в счет) и ограниченность одной парадигмой структурного программирования делает этот язык крайне дорогим в поддержке. Так же этому (и быстрому прототипированию и дорогой поддержке кода) способствует лютая ненависть создателей языка к принципу DRY.
    Rust имеет такую редкую сегодня строгую типизацию, одним из нюансов которой являются концепции владения и заимствования (которые позволяют делать автоматическое управление памятью в compile time), что порождает с одной стороны высокий порог входа в технологию (что сглаживается человекопонятным выводом компилятора, если входящие умеют читать, что еще более редко встречается сегодня, чем строгая типизация), но так же удешевляет поддержку продукта длительное время. Так же надо понимать, что Rust не спасет от кривых рученок быдлокодеров (разве что они не смогут его освоить), так как при большом желании можно сделать и утечки памяти и дедлоки и гонки данных (хотя в Golang это все сделать на порядок проще).
    Ну и надо не забывать, что много где присутствует hype-driven-development и Golang распиарен, а Rust нет.
    Ответ написан
    3 комментария
  • Собираюсь идти в сферу программирования. Изучаем в школе языки. Какой лучше выучить Pascal или C++?

    solotony
    @solotony
    покоряю пик Балмера
    в качестве учебного языка паскаль лучше. а когда начнете работать поймете что язык всего лишь инструмент, который выбирается под задачу

    а всем кто советует С++ можно ответить просто - rust
    Ответ написан
    2 комментария
  • Собираюсь идти в сферу программирования. Изучаем в школе языки. Какой лучше выучить Pascal или C++?

    dom1n1k
    @dom1n1k
    Если выбор стоит только между этими двумя и других вариантов нет - Паскаль.
    Да, он сейчас почти не применим в реальной практике. Но как первый учебный язык он лучше. C++ слишком сложен для человека с нулевой базой.
    А уже позднее перейти на другие языки - может быть, тот же C++, а может быть что-то третье.
    Сменить язык в ходе карьеры, причем скорее всего даже не один раз - это нормально.
    Ответ написан
  • Rust - ещё один убийца c/c++?

    @deliro
    Rust лучше С/С++ во многих (наверное, почти всех) аспектах. Но в сравнении с С++ и тем более Си он слишком молод. Непопулярность языка ещё обуславливается тем, что рынок полностью забит Си и плюсами — миллионы строк кода и библиотек уже написаны на С/С++. Кто их будет переписывать?

    Так же, не было никакой значимой маркетинговой кампании по популяризации Rust. Я случайно услышал об этом языке на Moscow Python Conf++, до этого я думал, что когда говорят про Rust, имеют ввиду игру.

    Плюс, Rust — язык очень нишевый, как и С/С++. И эта ниша — системное или околосистемное программирование. Операционные системы, драйвера, высокопроизводительные системы, игровые (и любые другие) движки, embed — вот удел раста. И в этих сферах не принято, как, например, в JS'е менять фреймворки и версии языка раз в неделю. Сообщество там крайне консервативное.

    К тому же, у Rust очень высокий порог входа. Вот прям очень. Если в контексте C++ постоянно шутят про книги "выучить С++ за 24 часа", то в контексте Rust можно шутить над книгами "выучить Rust за неделю". У их прекрасной парадигмы zero-cost abstractions на самом деле есть cost — сложность понимания. За отсутствие сборщика мусора и необходимости чистить за собой память придётся заплатить многими часами войны с компилятором, а именно — с borrow checker'ом. И это только одна сложность

    Когда начинаешь понимать Rust, всё идёт прям отлично. Но до этого момента придётся пройти ад и Израиль, который С/С++'еры не хотят проходить. Потому что они уже его прошли, когда учили С/С++ и там было намного хуже.

    Я бы очень хотел, чтобы Rust заменил С/С++, он объективно лучше. Но вряд ли это произойдёт в ближайшие лет 10
    Ответ написан
    6 комментариев
  • Правда ли, что в области высокопроизводительных приложений за Rust'ом будущее?

    @humbug
    > Сможет Rust ли в будущем стать быстрее С/С++?

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

    > Правда ли, что в области высокопроизводительных приложений за Rust'ом будущее?

    Цель Rust заключается в безопасности, скорость - это приятное дополнение.

    Ну а стоит его учить или нет, смотри по фактам:

    • Криптобиржи пишут на Rust (надежность)
    • Есть вакансии в Мск за 300к рублей в месяц на руки (доходность)
    • В github Rust в 5-ке языков по популярности, а на SO это самый любимый язык (интерес)
    • https://www.techempower.com/blog/2018/06/06/framew... (производительность)
    Ответ написан
    2 комментария