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();
}
Я обернул создание отдельного потока в функцию и так передавал в поток данные. Удобно, что такую функцию могу вынести в отдельный файл-модуль. Но не смог такое сделать динамически в цикле для группы потоков. Хочу подойти к варианту, когда поток, который закончил выполнение своего кода (раньше других), можно опять запустить из 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();
}
use std::env::current_exe;
fn main() {
let x = current_exe();
println!("{x:?}")
}
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
}
}
}
чтоб на Raspberry Pi4 потянули.
Насколько критичной проблемой для программиста является ручное управление памятью, которое называют недостатком языка Си?Неосвобожденная память (утечка памяти) - это самое безобидное, что может произойти.
Новый язык программирования Раст, как заявляют, лишен этого недостатка
но разве число ошибок в программе зависит именно от наличия или отсутствия ручного управления памятьюВ Rust ручное управление памятью, как и в C и в C++, просто есть культура, что если некая структура аллоцировала память, то она ее освободит. Всякие Vec, Box и т.д. делают это в Drop. В C++ многие повседневные типы так же освобождают в деструкторе память, которую они выделили. Однако в Rust есть разделение на safe и unsafe код и для прикладного программирования safe возможностей более чем достаточно. В C++ же весь код unsafe.
разве общее число ошибок не перераспределяется на другие недостатки программыНет, не перераспределяется. Хорошая система типов действительно может избавить от многих ошибок, что в целом сделает ПО более надежным. Но надо понимать, что от всех ошибок не избавит ни что. Банальная дискоммуникация с заказчиком порождает огромное число багов.
являются ли ошибки с памятью ошибками программиста, а не компилятора и языка программированияБезусловно это ошибки программиста. Программисты, как правило, - это люди, а людям свойственно ошибаться. И хорошо, когда есть средства статического анализа, которые помогают предотвращать ошибки до выхода ПО в продакшн.
Насколько критичной проблемой для программиста является ручное управление памятью, которое называют недостатком языка Си?
Новый язык программирования Раст, как заявляют, лишен этого недостатка
разве общее число ошибок не перераспределяется на другие недостатки
являются ли ошибки с памятью ошибками программиста
которые вылились бы в другое русло, не будь этой возможности ошибочного использования памяти?
Какие задачи решают на Rustлюбые. Rust - язык общего назначения, применимый к большинству возможных задач. Rust достаточно высокоуровневый для написания на нем прикладного ПО и компилируется в достаточно эффективный машинный код, для применения в ядрах ОС, драйверах или embedded разработке. Так же Rust на сегодня имеет самый маленький размер при компиляции в wasm, что критично для использования в web. Я честно не знаю такой сферы, к которой бы не подошел Rust.
а какие на GolangGolang тоже язык общего назначения, но имеющий ряд ограничений:
Можно один заменить другим?Rust спокойно заменяет Golang в любой возможной на последнем задаче, наоборот же иногда имеем ряд ограничений.