Threads
Создание
Потоки - объект ОС, способ разделения работы ПО. На обработку потоков могут назначаться разные ядра, а могут и не назначаться. Потоки выгодно использовать тогда, когда они дают выигрыш во времени больше, чем время на их создание (на x86 процессорах = ~9000 наносек, на ARM процессорах = ~27000 наносек). Обычно, это интенсивные по вычислениям приложения. Для интенсивным по вводу-выводу приложений следует использовать async/await вместо потоков.
Пример создания:
fn hello_thread() {
println!("Hello from thread")
}
fn main() {
println!("Hello from the MAIN thread");
let thread_handle = std::thread::spawn(hello_thread);
thread_handle.join().unwrap(); // нужно соединить новый поток с главным
// потоком программы, иначе он может не успеть вернуть данные до
// завершения главного потока программы
}
Потоки являются владельцами данных, поэтому нужно передавать им данные перемещением, чтобы они были живы к моменту запуска потока:
fn do_math(i: u32) -> u32 {
let mut n = i + 1;
for _ in 0..10 {
n *= 2;
}
n
}
fn main() {
println!("Hello from the MAIN thread");
let mut thread_handles = Vec::new(); // вектор указателей потоков
for i in 0..10 {
let thread_handle = std::thread::spawn(move || do_math(i));
thread_handles.push(thread_handle); // добавить поток к вектор
}
for h in thread_handles.into_iter() {
println!("{}", h.join().unwrap()); // соединение потоков с главным.
} // и вывод результата каждого потока.
Разделение задачи на потоки
Простой вариант - поделить вектор со значениями на куски (chunks), и под обработку каждого куска сделать отдельный поток, после чего собрать потоки вместе:
fn main() {
const N_THREADS: usize = 8;
let to_add = (0..5000).collect::<Vec<u32>>(); // вектор от 0 до 4999
let mut thread_handles = Vec::new(); // вектор указателей потоков
let chunks = to_add.chunks(N_THREADS); // размер кусков разбиения
for chunk in chunks {
let my_chunk = chunk.to_owned(); // обход borrow checker/lifetime
thread_handles.push(std::thread::spawn(move || my_chunk.iter().sum::<u32>())); // создание потоков с принадлежащими им данными
}
// суммирование потоков-кусков в одно число
let mut sum: u32 = 0;
for handle in thread_handles {
sum += handle.join().unwrap()
}
println!("Sum is {sum}");
}