today's studying

This commit is contained in:
Rorik Star Platinum 2025-12-04 23:25:29 +03:00
parent 171c8d5489
commit 71db955e55
10 changed files with 446 additions and 2 deletions

View file

@ -0,0 +1,70 @@
Отличный и глубокий вопрос! На него часто дают неполный ответ ("перемещается замыкание"), но давайте разберем **конкретно по байтам**, что именно физически перемещается в новый поток в вашем коде.
### Короткий ответ
Когда вы пишете `move ||`, в новый поток перемещается **сама структура замыкания** (closure struct).
В вашем случае эта структура имеет размер всего 8 байт (на 64-битной системе) и содержит внутри **только один `Arc`**.
### Подробный разбор ("под капот")
#### 1. Что такое замыкание в Rust?
Компилятор Rust превращает ваше замыкание в анонимную структуру (struct). Поля этой структуры — это все переменные из внешнего окружения, которые вы захватили.
В вашем коде внутри `thread::spawn`:
```rust
move || {
// Используются:
// 1. i (копия, примитив)
// 2. chunk_size (копия, примитив)
// 3. data_ref (это Arc<Vec<i32>>)
// ... логика
}
```
Компилятор генерирует примерно такую структуру:
```rust
// Псевдокод сгенерированной структуры
struct ClosureEnvironment {
i: usize, // 8 байт
chunk_size: usize, // 8 байт
data_ref: Arc<Vec<i32>>, // 8 байт (указатель на кучу)
}
```
#### 2. Что делает `move`?
Ключевое слово `move` приказывает компилятору: "Забери владение всеми переменными, которые используются внутри `{...}`, и положи их в эту структуру `ClosureEnvironment`".
Без `move` компилятор попытался бы положить в структуру **ссылки** (`&i`, `&data_ref`), что вызвало бы ошибку компиляции, так как ссылки не могут пережить функцию `sum_squares_static_arc`.
#### 3. Что физически "перемещается"?
Когда вы вызываете `thread::spawn(move || ...)`:
1. Создается экземпляр этой структуры `ClosureEnvironment` на стеке текущего потока.
2. Этот экземпляр **перемещается** (memcpy) из стека главного потока в стек нового потока (или в кучу, если `Box::new`).
* `i` и `chunk_size` просто копируются (как `Copy` типы).
* `data_ref` (`Arc`) тоже копируется (бинарно это просто указатель `0x...`). **Сами данные массива `[i32]` никуда не копируются**, они лежат в куче и остаются на месте. Копируется только "умный указатель" на них.
### Итоговая картина
В новый поток "улетает" маленький пакет данных (размером 24 байта: `usize` + `usize` + `ptr`), который содержит:
1. Число `i` (индекс потока).
2. Число `chunk_size`.
3. Указатель `Arc` (который увеличил счетчик ссылок на данные, но сами данные не трогал).
В этом и есть суть эффективности: вы передаете гигабайты данных в другой поток, физически перемещая всего 8 байт указателя `Arc`.
### Важное уточнение про `Arc`
Обратите внимание, что перед циклом вы делаете:
```rust
let data_ref = Arc::clone(&data_arc);
```
Именно этот **новый** `data_ref` перемещается в замыкание. Оригинальный `data_arc` остается в `main` потоке нетронутым.
Каждая итерация цикла создает свой собственный "билетик" (`data_ref`), и именно этот билетик `move` забирает в новый поток.
[1](https://doc.rust-lang.org/std/sync/struct.Arc.html)
[2](https://stackoverflow.com/questions/72251938/implement-thread-safe-function-object-in-rust)
[3](http://rust-unofficial.github.io/too-many-lists/third-arc.html)
[4](https://users.rust-lang.org/t/implementing-thread-safe-structs-for-tokio/21658)
[5](https://onesignal.com/blog/thread-safety-rust/)
[6](https://www.rustfinity.com/blog/what-is-thread-safety)
[7](https://rust-training.ferrous-systems.com/latest/book/thread-safety)
[8](https://forums.swift.org/t/arc-automatic-reference-counting-is-thread-safe/63899)
[9](https://www.ardanlabs.com/blog/2024/11/fearless-concurrency-ep6-understanding-rust-arc-for-efficient-multithreading.html)