use std::thread;
// Это главный поток
fn main() {
// Это данные, которые мы будем обрабатывать.
// Мы посчитаем сумму всех чисел при помощи разделённого на потоки map-reduce алгоритма.
// Каждый фрагмент, разделённый пробелами, будет обрабатываться в отдельном потоке.
//
// TODO: посмотрите, что случится, если вы добавите пробелов!
let data = "86967897737416471853297327050364959
11861322575564723963297542624962850
70856234701860851907960690014725639
38397966707106094172783238747669219
52380795257888236525459303330302837
58495327135744041048897885734297812
69920216438980873548808413720956532
16278424637452589860345374828574668";
// Создадим вектор, который будет содержать созданные нам дочерние потоки.
let mut children = vec![];
/*************************************************************************
* "Map" фаза
*
* Разделим наши данные на сегменты и запустим начальную обработку
************************************************************************/
// Разделим наши данные на сегменты для индивидуального вычисления.
// Каждый фрагмент будет ссылкой (&str) на данные.
let chunked_data = data.split_whitespace();
// Обойдём сегменты данных.
// .enumerate() добавит в текущий цикл индекс элемента
// и далее полученный кортеж "(index, element)" будет немедленно
// "деструктурирован" на две переменные, "i" и "data_segment", при помощи
// "деструктурирующего присваивания"
for (i, data_segment) in chunked_data.enumerate() {
println!("{} сегмент данных \"{}\"", i, data_segment);
// Обработаем каждый сегмент данных в отдельном потоке
//
// `spawn()` вернёт ручку на новый поток,
// которую мы ДОЛЖНЫ сохранить, чтобы иметь доступ к возвращённому значению
//
// Синтаксис 'move || -> u32' обозначает замыкание, которое:
// * не имеет аргументов ('||')
// * забирает владение захваченных переменных ('move')
// * возвращает беззнаковое 32-битное целое число ('-> u32')
//
// Rust может вывести '-> u32' из самого замыкация,
// так что мы можем его опустить.
//
// TODO: попробуйте удалить 'move' и посмотреть что получится
children.push(thread::spawn(move || -> u32 {
// Вычислим промежуточную сумму этого сегмента:
let result = data_segment
// итерируемся по символам этого сегмента..
.chars()
// .. преобразуем текстовые символы в их числовые значения..
.map(|c| c.to_digit(10).expect("должно быть числом"))
// .. и суммируем получившийся итератор из чисел
.sum();
// `println!` блокирует стандартный вывод, так что чередования текста не происходит
println!("обработан сегмент {}, result={}", i, result);
// "return" не обязателен, так как Rust "язык выражений" и
// последнее выполненное выращение в каждом блоке автоматически становится значением этого блока.
result
}));
}
/*************************************************************************
* Фаза "Reduce"
*
* Собираем наши промежуточные значения и объединяем их в конечные результат
************************************************************************/
// собираем промежуточный результат каждого потока в новый вектор
let mut intermediate_sums = vec![];
for child in children {
// собираем возвращаемое значение каждого дочернего потока
let intermediate_sum = child.join().unwrap();
intermediate_sums.push(intermediate_sum);
}
// Объединяем все промежуточные суммы в одну конечную сумму.
//
// Мы используем "turbofish" `::<>` чтобы подсказать `sum()` тип.
//
// TODO: попробуйте без turbofish, явно указывая тип final_result
let final_result = intermediate_sums.iter().sum::<u32>();
println!("Финальная сумма: {}", final_result);
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX