目次

Rustの勉強[並行性 その1]

ぎじゅつ

はじめに

#

NO IMAGEThe Rust Programming Language 日本語版 - The Rust Programming Language 日本語版
を読んでいる

お勉強

#
  • ポインタ終わった
    • 実装したらもうちょっと理解度はあがりそう
  • 並行処理やる
  • 恐れるな!並行性
    • タイトルがいい
  • 結構ワクワクしている

NO IMAGE恐れるな!並行性 - The Rust Programming Language 日本語版

メモ

#
  • さらっと読んでみる

並行性を安全かつ効率的に扱うことは、Rustの別の主な目標です。

  • そうなんだ

メモリ安全性を保証することと、並行性問題を回避することは、 異なる方法で解決すべき別々の課題だと考えていました。

  • ほうほう

所有権と型システムは、 メモリ安全性と並行性問題を管理する役に立つ一連の強力な道具であることを発見しました。

  • 発見する
    • jsonも発見された

多くの並行性エラーは、実行時エラーではなくコンパイル時エラーになります。

  • すごすぎじゃん

Rustは、自分の状況と必要性に適した方法が何であれ、問題をモデル化するためのいろんな道具を備えています。

  • ここRustっぽい
    • 機能多すぎじゃね?って議論されていたの思い出した

NO IMAGEスレッドを使用してコードを同時に走らせる - The Rust Programming Language 日本語版

  • とりあえず光らせとくか

    • spawnとかjoinがでてくるな
    • ちょろっとやったtokioの並行処理にあったわこんなの
    • moveクロージャの使い方は知りたかった
  • ほうほう

    • spawnでスレッド作って
    • joinで結果をマージして
    • moveでなんかする?
    • と読めた
  • なのでmoveがわからない

thread::spawnに渡されるクロージャでは、moveキーワードを多用することになるでしょう。 そうすることで、クロージャは環境から使用する値の所有権を奪い、あるスレッドから別のスレッドに値の所有権を移すからです。

  • ひとつのスレッドに所有権を集めておいたほうがいいってことかな

NO IMAGEはじめに - The Rust Programming Language 日本語版

  • これはじめてしった
    • わかりずら
use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(|| {
        //       "こちらがベクタ: {:?}"
        println!("Here's a vector: {:?}", v);
    });

    handle.join().unwrap();
}
  • かなり読める

クロージャはvを使用しているので、vをキャプチャし、クロージャの環境の一部にしています。 thread::spawnはこのクロージャを新しいスレッドで走らせるので、 その新しいスレッド内でvにアクセスできるはずです。しかし、このコードをコンパイルすると、 以下のようなエラーが出ます:

$ cargo run
   Compiling threads v0.1.0 (file:///projects/threads)
error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function
(エラー: クロージャは現在の関数よりも長生きするかもしれませんが、現在の関数が所有している`v`を借用しています)
 --> src/main.rs:6:32
  |
6 |     let handle = thread::spawn(|| {
  |                                ^^ may outlive borrowed value `v`
  |                                  (借用されている値`v`より長生きするかもしれません)
7 |         println!("Here's a vector: {:?}", v);
  |                                           - `v` is borrowed here
  |                                            (`v`はここで借用されています)
  |
note: function requires argument type to outlive `'static`
(注釈: 関数は引数型が`'static`より長生きすることを要求しています)
 --> src/main.rs:6:18
  |
6 |       let handle = thread::spawn(|| {
  |  __________________^
7 | |         println!("Here's a vector: {:?}", v);
8 | |     });
  | |______^
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
(ヘルプ: `v`(や他の参照されている変数)の所有権をクロージャに奪わせるには、`move`キーワードを使用してください)
  |
6 |     let handle = thread::spawn(move || {
  |                                ++++

For more information about this error, try `rustc --explain E0373`.
error: could not compile `threads` (bin "threads") due to 1 previous error
  • ほー

コンパイラには、立ち上げたスレッドがどのくらいの期間走るのかわからないので、 vへの参照が常に有効であるか把握できないのです。

  • そらそうだ
    • 平行で動くなら尚更
use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(move || {
        println!("Here's a vector: {:?}", v);
    });

    handle.join().unwrap();
}
  • こうしてみる
$ cargo run
   Compiling threads v0.1.0 (file:///projects/threads)
error[E0382]: use of moved value: `v`
(エラー: ムーブされた値の使用: `v`)
  --> src/main.rs:10:10
   |
4  |     let v = vec![1, 2, 3];
   |         - move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
   |          (`v``Copy`トレイトを実装しない`Vec<i32>`型を持つので、ムーブが発生します)
5  |
6  |     let handle = thread::spawn(move || {
   |                                ------- value moved into closure here
   |                                       (値はここでクロージャ内にムーブされます)
7  |         println!("Here's a vector: {:?}", v);
   |                                           - variable moved due to use in closure
   |                                            (変数はクロージャ内で使用されているためムーブされます)
...
10 |     drop(v); // oh no!
   |          ^ value used here after move
   |           (値はここでムーブ後に使用されています)

For more information about this error, try `rustc --explain E0382`.
error: could not compile `threads` (bin "threads") due to 1 previous error
  • こうなるらしい
  • はえー
  • moveもそうだけどcopyトレイトがあるかどうかで判断しているんだな

まとめ

#
  • 並行処理で所有権を使うことは有効だった
  • spawnjoinmoveクロージャが紹介されていた

次はここのspawnjoinの認識ミスがないかを確認する

NO IMAGEスレッドを使用してコードを同時に走らせる - The Rust Programming Language 日本語版

問題

  • moveは何で使うのか