mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-17 06:47:49 +00:00
Merge branch 'main' into tm-translate-post-12-ru
This commit is contained in:
@@ -245,7 +245,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
Aquí leemos el archivo `foo.txt` y luego usamos el combinador [`then`] para encadenar un segundo futuro basado en el contenido del archivo. Si la longitud del contenido es menor que lo dado en `min_len`, leemos un archivo diferente `bar.txt` y se lo anexamos a `content` usando el combinador [`map`]. De lo contrario, solo devolvemos el contenido de `foo.txt`.
|
||||
|
||||
@@ -285,7 +285,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
Esta función es una traducción directa de la función `example` de [arriba](#desventajas) que usó funciones combinadoras. Usando el operador `.await`, podemos recuperar el valor de un futuro sin necesitar closures o tipos `Either`. Como resultado, podemos escribir nuestro código como escribimos código síncrono normal, con la diferencia de que _esto sigue siendo código asíncrono_.
|
||||
|
||||
@@ -580,7 +580,7 @@ println!("valor en: {:p}", &stack_value);
|
||||
println!("referencia interna: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Pruébalo en el playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
Aquí usamos la función [`mem::replace`] para reemplazar el valor asignado en el heap con una nueva instancia de estructura. Esto nos permite mover el valor original `heap_value` a la pila, mientras que el campo `self_ptr` de la estructura es ahora un puntero colgante que aún apunta a la antigua dirección del heap. Cuando intentas ejecutar el ejemplo en el playground, verás que las líneas impresas _"valor en:"_ y _"referencia interna:"_ muestran punteros diferentes. Por lo tanto, la asignación de un valor en el heap no es suficiente para hacer que las auto-referencias sean seguras.
|
||||
|
||||
@@ -629,24 +629,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
Además de cambiar `Box::new` a `Box::pin`, también necesitamos añadir el nuevo campo `_pin` en el inicializador de la estructura. Dado que `PhantomPinned` es un tipo de tamaño cero, solo necesitamos su nombre de tipo para inicializarlo.
|
||||
|
||||
Cuando [intentamos ejecutar nuestro ejemplo ajustado](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) ahora, vemos que ya no funciona:
|
||||
Cuando [intentamos ejecutar nuestro ejemplo ajustado](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) ahora, vemos que ya no funciona:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
Ambos errores ocurren porque el tipo `Pin<Box<SelfReferential>>` ya no implementa el trait `DerefMut`. Esto es exactamente lo que queremos porque el trait `DerefMut` devolvería una referencia `&mut`, que queremos prevenir. Esto solo ocurre porque ambos optamos por no implementar `Unpin` y cambiamos `Box::new` a `Box::pin`.
|
||||
|
||||
@@ -250,7 +250,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
ここでは、ファイル `foo.txt` を読み込んでから、[`then`] コンビネータを使って、ファイルの内容に基づいて 2 番目の future を連鎖させています。もしコンテンツの長さが与えられた `min_len` よりも小さければ、別の `bar.txt` ファイルを読み込んで、[`map`] コンビネータを使って `content` に追加します。それ以外の場合は、`foo.txt` の内容のみを返します。
|
||||
|
||||
@@ -290,7 +290,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
この関数は、[上記](#drawbacks)のコンビネータ関数を使った `example` 関数をそのまま翻訳したものです。 `.await` 演算子を使うことで、クロージャや `Either` 型を必要とせずに future の値を取得することができます。その結果、まるで通常の同期コードを書いているかのように非同期コードを書くことができます。
|
||||
|
||||
@@ -572,7 +572,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
`SelfReferential` という名前のシンプルな構造体を作成します。この構造体には1つのポインタフィールドが含まれます。まず、この構造体をNULLポインタで初期化し、`Box::new`を使ってヒープ上に確保します。次に、ヒープに割り当てられた構造体のメモリアドレスを決定し、それを `ptr` 変数に格納します。最後に、`ptr`変数を`self_ptr`フィールドに代入して、構造体を自己参照にします。
|
||||
|
||||
@@ -588,7 +588,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
ここでは、[`mem::replace`]関数を使用して、ヒープに割り当てられた値を新しい構造体のインスタンスで置き換えています。これにより、元の `heap_value` をスタックに移動させることができますが、構造体の `self_ptr` フィールドは、古いヒープアドレスを指し示すダングリングポインタになっています。この例をplaygroundで実行してみると、出力された **"value at:"** と **"internal reference:"** の行には、たしかに異なるポインタが表示されていることがわかります。つまり、値をヒープに割り当てるだけでは、自己参照を安全にするには不十分なのです。
|
||||
|
||||
@@ -637,24 +637,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
`Box::new` を `Box::pin` に変更することに加えて、構造体を初期化するコード(イニシャライザ)に新しい `_pin` フィールドを追加する必要があります。`PhantomPinned` はゼロサイズの型なので、初期化に必要なのはその型名だけです。
|
||||
|
||||
今、[調整した例を実行してみると](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a)、動作しなくなっていることがわかります:
|
||||
今、[調整した例を実行してみると](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a)、動作しなくなっていることがわかります:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
どちらのエラーも、`Pin<Box<SelfReferential>>` 型が `DerefMut` trait を実装しなくなったために発生します。これはまさに求めていた結果であり、というのも、`DerefMut` trait は `&mut` 参照を返してしまうからで、私達はこれを防ぎたかったのです。これは、`Unpin` を使用しないようにして、`Box::new` を `Box::pin` に変更したからこそ起こる現象です。
|
||||
@@ -671,7 +671,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
[`get_unchecked_mut`] 関数は `Pin<Box<T>>` ではなく `Pin<&mut T>` に対して動作するため、事前に [`Pin::as_mut`] を使用して値を変換する必要があります。その後、`get_unchecked_mut` が返す `&mut` 参照を使って、`self_ptr` フィールドを設定することができます。
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
Here we read the file `foo.txt` and then use the [`then`] combinator to chain a second future based on the file content. If the content length is smaller than the given `min_len`, we read a different `bar.txt` file and append it to `content` using the [`map`] combinator. Otherwise, we return only the content of `foo.txt`.
|
||||
|
||||
@@ -285,7 +285,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
This function is a direct translation of the `example` function from [above](#drawbacks) that used combinator functions. Using the `.await` operator, we can retrieve the value of a future without needing any closures or `Either` types. As a result, we can write our code like we write normal synchronous code, with the difference that _this is still asynchronous code_.
|
||||
|
||||
@@ -566,7 +566,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
We create a simple struct named `SelfReferential` that contains a single pointer field. First, we initialize this struct with a null pointer and then allocate it on the heap using `Box::new`. We then determine the memory address of the heap-allocated struct and store it in a `ptr` variable. Finally, we make the struct self-referential by assigning the `ptr` variable to the `self_ptr` field.
|
||||
|
||||
@@ -582,7 +582,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
Here we use the [`mem::replace`] function to replace the heap-allocated value with a new struct instance. This allows us to move the original `heap_value` to the stack, while the `self_ptr` field of the struct is now a dangling pointer that still points to the old heap address. When you try to run the example on the playground, you see that the printed _"value at:"_ and _"internal reference:"_ lines indeed show different pointers. So heap allocating a value is not enough to make self-references safe.
|
||||
|
||||
@@ -631,24 +631,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
In addition to changing `Box::new` to `Box::pin`, we also need to add the new `_pin` field in the struct initializer. Since `PhantomPinned` is a zero-sized type, we only need its type name to initialize it.
|
||||
|
||||
When we [try to run our adjusted example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) now, we see that it no longer works:
|
||||
When we [try to run our adjusted example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) now, we see that it no longer works:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
Both errors occur because the `Pin<Box<SelfReferential>>` type no longer implements the `DerefMut` trait. This is exactly what we wanted because the `DerefMut` trait would return a `&mut` reference, which we wanted to prevent. This only happens because we both opted-out of `Unpin` and changed `Box::new` to `Box::pin`.
|
||||
@@ -665,7 +665,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
The [`get_unchecked_mut`] function works on a `Pin<&mut T>` instead of a `Pin<Box<T>>`, so we have to use [`Pin::as_mut`] for converting the value. Then we can set the `self_ptr` field using the `&mut` reference returned by `get_unchecked_mut`.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ date = 2020-03-27
|
||||
[extra]
|
||||
chapter = "Multitasking"
|
||||
# Please update this when updating the translation
|
||||
translation_based_on_commit = "f2966a53489a1c3eff3e5c3c1c82a3febb47569b"
|
||||
translation_based_on_commit = "b2e12433b94a39d2437c2a472a3fd7cc4c22edab"
|
||||
# GitHub usernames of the people that translated this post
|
||||
translators = ["TakiMoysha"]
|
||||
|
||||
@@ -17,7 +17,7 @@ translators = ["TakiMoysha"]
|
||||
|
||||
<!-- more -->
|
||||
|
||||
Этот блог открыто разрабатывается на [GitHub]. Если у вас возникают проблемы или вопросы, пожалуйста, откройте issue. Также вы можете оставлять комментарии [внизу][at the bottom]. Исходный код этого поста можно найти в [`post-12` ветку][post branch].
|
||||
Этот блог открыто разрабатывается на [GitHub]. Если у вас возникают проблемы или вопросы, пожалуйста, откройте issue. Также вы можете оставлять комментарии [внизу][at the bottom]. Исходный код этого поста можно найти в [`post-12`][post branch].
|
||||
|
||||
[GitHub]: https://github.com/phil-opp/blog_os
|
||||
[at the bottom]: #comments
|
||||
@@ -36,7 +36,7 @@ translators = ["TakiMoysha"]
|
||||
|
||||
Одноядерные центральные процессоры (ЦП) могут выполнять только одну задачу за раз, а многоядерные ЦП могут выполнять несколько задач по настоящему параллельно. Например, процессор с 8 ядрами может выполнять 8 задач одновременно. В следующей статье мы расскажем, как настроить многоядерные ЦП <!-- hot to setup multi-core CPUs -->. В этой статье для простоты мы сосредоточимся на одноядерных процессорах. (Стоит отметить, что все многоядерные ЦП запускаются с одним активным ядром, поэтому пока мы можем рассматривать их как одноядерные процессоры).
|
||||
|
||||
Есть две формы многозадачности: _кооперативная_ или совместная (_cooperative_) - требует, чтобы задачи регулярно отдавали контроль над процессором для продвижения других задач; _вытесняющая_ или приоритетная () _preemptive_) - использующая функционал операционной системы (ОС) для переключения потоков в произвольные моменты моменты времени через принудительную остановку. Далее мы рассмотрим две формы многозадачности более подробно и обсудим их преимущества и недостатки.
|
||||
Есть две формы многозадачности: _кооперативная_ или совместная (_cooperative_) - требует, чтобы задачи регулярно отдавали контроль над процессором для продвижения других задач; _вытесняющая_ или приоритетная (_preemptive_) - использующая функционал операционной системы (ОС) для переключения потоков в произвольные моменты моменты времени через принудительную остановку. Далее мы рассмотрим две формы многозадачности более подробно и обсудим их преимущества и недостатки.
|
||||
|
||||
### Вытесняющая Многозадачность
|
||||
|
||||
@@ -250,7 +250,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
Здесь мы читаем файл `foo.txt`, а затем используем комбинатор [`then`], чтобы связать вторую футуру на основе содержимого файла. Если длина содержимого меньше заданного `min_len`, мы читаем другой файл `bar.txt` и добавляем его к `content` с помощью комбинатора [`map`]. В противном случае возвращаем только содержимое `foo.txt`.
|
||||
|
||||
@@ -302,7 +302,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
Эта ф-ция - прямой перевод `example` написанной [выше](#Недостатки), которая использовала комбинаторы. Используя оператор `.await`, мы можем получить значение футуры без необходимости использования каких-либо замыканий или типов `Either`. В результате, мы можем писать наш код так же, как если бы это был обычный синхронный код, с той лишь разницей, что _это все еще асинхронный код_.
|
||||
|
||||
@@ -583,7 +583,7 @@ struct SelfReferential {
|
||||
|
||||
([Попробовать][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
Мы создаем простую структуру с названием `SelfReferential`, которая содержит только одно поле c указателем. Во-первых, мы инициализируем эту структуру с пустым указателем и затем выделяем место в куче с помощью `Box::new`. Затем мы определяем адрес кучи для выделенной структуры и храним его в переменной `ptr`. В конце концов, мы делаем структуру самоссылающейся, назначив переменную `ptr` полю `self_ptr`.
|
||||
|
||||
@@ -599,7 +599,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
Мы используем функцию [`mem::replace`], чтобы заменить значение, выделенное в куче, новым экземпляром структуры. Это позволяет нам переместить исходное значение `heap_value` в стек, в то время как поле `self_ptr` структуры теперь является висящим указателем, который по-прежнему указывает на старый адрес в куче. Когда вы запустите пример в песочнице, вы увидите, что строки _«value at:»_ и _«internal reference:»_, показывают разные указатели. Таким образом, выделение значения в куче недостаточно для обеспечения безопасности самоссылок.
|
||||
|
||||
@@ -648,10 +648,10 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
В дополнение к изменению `Box::new` на `Box::pin`, нам также нужно добавить новое поле `_pin` в инициализатор структуры. Т.к. `PhantomPinned` является типом нулевого размера, нам нужно только его имя типа для инициализации.
|
||||
|
||||
Когда мы [попробуем запустить наш скорректированный пример](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) сейчас, он больше не работает:
|
||||
Когда мы [попробуем запустить наш скорректированный пример](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) сейчас, он больше не работает:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
@@ -659,13 +659,13 @@ error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxe
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
Обе ошибки возникают потому, что тип `Pin<Box<SelfReferential>>` больше не реализует трейт `DerefMut`. Это именно то, чего мы хотели, поскольку трейт `DerefMut` возвращал бы ссылку `&mut`, что мы и хотели предотвратить. Это происходит только потому, что мы отказались от `Unpin` и изменили `Box::new` на `Box::pin`.
|
||||
@@ -682,7 +682,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Попробовать](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
Функция [`get_unchecked_mut`] работает с `Pin<&mut T>` вместо `Pin<Box<T>>`, поэтому нам нужно использовать [`Pin::as_mut`] для преобразования значения. Затем мы можем установить поле `self_ptr`, используя ссылку `&mut`, возвращаемую `get_unchecked_mut`.
|
||||
|
||||
@@ -1836,4 +1836,4 @@ impl Executor {
|
||||
|
||||
Используя async/await, мы теперь имеем базовую поддержку кооперативной мультизадачности в нашем ядре. Хотя кооперативная мультизадачность очень эффективна, она может привести к проблемам с задержкой, когда отдельные задачи выполняются слишком долго, тем самым препятствуя выполнению других задач. По этой причине имеет смысл также добавить поддержку вытесняющей мультизадачности в наше ядро.
|
||||
|
||||
В следующем посте мы введём _потоки_ как наиболее распространённую форму вытесняющей мультизадачности. В дополнение к решению проблемы долгозадачных задач, потоки также подготовят нас к использованию нескольких ядер процессора и запуску ненадежных пользовательских программ в будущем.
|
||||
В следующем посте мы введём _потоки_ как наиболее распространённую форму вытесняющей мультизадачности. В дополнение к решению проблемы длительных задач, потоки также подготовят нас к использованию нескольких ядер процессора и запуску ненадежных пользовательских программ в будущем.
|
||||
|
||||
1834
blog/content/edition-2/posts/12-async-await/index.zh-CN.md
Normal file
1834
blog/content/edition-2/posts/12-async-await/index.zh-CN.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -301,7 +301,7 @@ fn example(min_len: usize) -> impl Future<Output = String> {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=91fc09024eecb2448a85a7ef6a97b8d8))
|
||||
|
||||
這裏我們讀取文件 `foo.txt`,然後使用 [`then`] 組合器 來連接 基於文件內容的第二個 future。
|
||||
如果內容的長度小於給定的 `min_len`,我們讀取一個不同的 `bar.txt` 文件並使用 [`map`] 組合器 將它附加到 `content` 上。
|
||||
@@ -348,7 +348,7 @@ async fn example(min_len: usize) -> String {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d93c28509a1c67661f31ff820281d434))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d93c28509a1c67661f31ff820281d434))
|
||||
|
||||
這個函數是對 [上面](#drawbacks) 的 `example` 函數的直接翻譯,它使用了組合器函數。
|
||||
使用 `.await` 運算符,我們可以獲取 future 的值而不需要任何閉包或 `Either` 類型。
|
||||
@@ -671,7 +671,7 @@ struct SelfReferential {
|
||||
|
||||
([Try it on the playground][playground-self-ref])
|
||||
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
[playground-self-ref]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce1aff3a37fcc1c8188eeaf0f39c97e8
|
||||
|
||||
我們創建了一個名為 `SelfReferential` 的簡單結構體,它包含一個單指針字段。首先,我們使用空指針初始化這個結構體,然後使用 `Box::new` 在堆上分配它。然後,我們確定堆分配的結構體的內存地址並將其存儲在 `ptr` 變量中。最後,我們通過將 `ptr` 變量賦值給 `self_ptr` 字段使結構體成為自引用。
|
||||
|
||||
@@ -689,7 +689,7 @@ println!("value at: {:p}", &stack_value);
|
||||
println!("internal reference: {:p}", stack_value.self_ptr);
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e160ee8a64cba4cebc1c0473dcecb7c8))
|
||||
|
||||
這裏我們使用 [`mem::replace`] 函數將堆分配的值替換為一個新的結構體實例。
|
||||
這允許我們將原始的 `heap_value` 移動到棧上,而結構體的 `self_ptr` 字段現在是一個懸空指針,它仍然指向舊的堆地址。
|
||||
@@ -746,24 +746,24 @@ let mut heap_value = Box::pin(SelfReferential {
|
||||
|
||||
除了將 `Box::new` 更改為 `Box::pin` 之外,我們還需要在結構體初始化程序中添加新的 `_pin` 字段。由於 `PhantomPinned` 是一個零大小的類型,我們只需要它的類型名稱來初始化它。
|
||||
|
||||
當我們 [嘗試運行我們調整後的例子](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=961b0db194bbe851ff4d0ed08d3bd98a) 時,我們看到它不再工作:
|
||||
當我們 [嘗試運行我們調整後的例子](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=961b0db194bbe851ff4d0ed08d3bd98a) 時,我們看到它不再工作:
|
||||
|
||||
```
|
||||
error[E0594]: cannot assign to data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
error[E0594]: cannot assign to data in dereference of `Pin<Box<SelfReferential>>`
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
10 | heap_value.self_ptr = ptr;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
|
||||
error[E0596]: cannot borrow data in a dereference of `std::pin::Pin<std::boxed::Box<SelfReferential>>` as mutable
|
||||
error[E0596]: cannot borrow data in dereference of `Pin<Box<SelfReferential>>` as mutable
|
||||
--> src/main.rs:16:36
|
||||
|
|
||||
16 | let stack_value = mem::replace(&mut *heap_value, SelfReferential {
|
||||
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::pin::Pin<std::boxed::Box<SelfReferential>>`
|
||||
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<Box<SelfReferential>>`
|
||||
```
|
||||
|
||||
由於 `Pin<Box<SelfReferential>>` 類型不再實現 `DerefMut` 特型,所以這兩個錯誤都發生了。
|
||||
@@ -783,7 +783,7 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
([Try it on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b9ebbb11429d9d79b3f9fffe819e2018))
|
||||
|
||||
[`get_unchecked_mut`] 函數在 `Pin<&mut T>` 上工作,而不是在 `Pin<Box<T>>` 上,因此我們必須使用 [`Pin::as_mut`] 來轉換值。
|
||||
然後我們可以使用 `get_unchecked_mut` 返回的 `&mut` 引用來設置 `self_ptr` 字段。
|
||||
|
||||
Reference in New Issue
Block a user