今年の言語はRust その６３

# 今年の言語はRust その６３

Rustを学びます

Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル(英語)
https://doc.rust-lang.org/book/


## 実行環境

```sh
$ cargo -V
cargo 1.33.0 (f099fe94b 2019-02-12)

$ rustup -V
rustup 1.17.0 (069c88ed6 2019-03-05)

$ rustc --version
rustc 1.33.0 (2aa4c46cf 2019-02-28)

$  cat /proc/version
Linux version 4.14.97-74.72.amzn1.x86_64 (mockbuild@gobi-build-64002) 
(gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC)) 
#1 SMP Tue Feb 5 20:59:30 UTC 2019

$ uname -a
Linux ip-10-100-0-8 4.14.97-74.72.amzn1.x86_64 
#1 SMP Tue Feb 5 20:59:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/\*release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2018.03

```

## 20. マルチスレッドのWebサーバーを構築する

やっとここまで来ました。最後の章です。

実はWebサーバーの仕組みが知りたくて知りたくて60回もやってきました。

以下がレッスン内容になります

- TCPとHTTPについて少し学ぶ。
- ソケットでTCP接続をリッスンする。
- 少量のHTTPリクエストを構文解析する。
- 適切なHTTPレスポンスを生成する。
- スレッドプールでサーバのスループットを強化する。

### 20.3 優雅なシャットダウンと片付け

#### *ThreadPool*に*Drop*トレイトを実装する


```rust

/// Dropの実装
impl Drop for ThreadPool {
	fn drop(&mut self) {
		for worker in &mut self.workers {
			println!("Shutting down worker {}", worker.id);
			worker.thread.join().unwrap();
		}
	}
}

```
まず、これはコンパイルエラーになる

```rust
>cargo check
    Checking hello v0.1.0 (H:\Dropbox\07_DevelopFolda\20190502_Rust\hello)
error[E0507]: cannot move out of borrowed content
  --> src\lib.rs:71:4
   |
71 |             worker.thread.join().unwrap();
   |             ^^^^^^^^^^^^^ cannot move out of borrowed content

error: aborting due to previous error

For more information about this error, try `rustc --explain E0507`.
error: Could not compile `hello`.

To learn more, run the command again with --verbose.
```

workerへは可変参照しかない。join()は所有権を奪うので、エラーとなる。

Workerの視点で考えると。*Worker.thread*は*None*を許容できない。
つまり、join()により所有権が奪われると*thread=None*となってしまうのでコンパイラに怒られるのだ。

Worker.threadにNoneを許すのであれば、*Option*を使用するのがよい。

```rust
struct Worker {
	id: usize,
	thread: thread::JoinHandle<()>,
}

```
書き換える

```Rust
struct Worker {
	id: usize,
	thread: Option<thread::JoinHandle<()>>,
}
```

Workerの生成時にSomeで囲います

```rust
impl Worker {
	fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>> ) -> Worker {

		// -- snip --

		Worker {
			id,
			thread: Some(thread)
		}
	}
}
```

*Option*型なので、*if let*構文を使って値を取り出します。
Noneの場合は、動きません。C++等でおなじみのnull回避のケースですね。

```rust
/// Dropの実装
impl Drop for ThreadPool {
	fn drop(&mut self) {
		for worker in &mut self.workers {
			println!("Shutting down worker {}", worker.id);

			if let Some(thread) = worker.thread.take() {
				thread.join().unwrap();
			}
		}
	}
}
```

#### スレッドに仕事をリッスンするのを止めるように通知する


```rust
/// スレッドの動作についての通知
enum Message {
	NewJob(Job),
	Terminate,
}

pub struct ThreadPool{
	workers: Vec<Worker>,
	sender: mpsc::Sender<Message> // Messageを送るSenderのこと
}

impl ThreadPool {

	pub fn execute<F>(&self, f: F)
		where F: FnOnce() + Send + 'static
	{
		let job = Box::new(f);

		// [-] self.sender.send(job).unwrap();
		self.sender.send(Message::NewJob(job)).unwrap(); // [+]
	}
}

impl Worker {
	fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>> ) -> Worker {

		let thread = thread::spawn(move || {

			loop {
				let message = receiver.lock().unwrap().recv().unwrap();

				// receiverにより、(senderから)受け取ったメッセージにより動作を決める
				match message {
					Message::NewJob(job) => {
						println!("Worker {:?} got a job; executing.", id);

						job.call_box();
					},
					Message::Terminate => {
						println!("Worker {:?} was told to terminate", id);

						break; // ループ終了
					}
				}
			}

		});

		Worker {
			id,
			thread: Some(thread)
		}
	}
}
```

#### まとめ

サーバーの実装を甘く見積もっていた。
ほとんどは非同期処理についてでした。
サンプルを通しただけではうまく理解できなかった

*自転車本*が*届いた*ので、別の側面から勉強を続けようと思う。

以上!





あと、5/8にRustの最新本がでるみたいです! 気が付いてラッキー！購入しました。 (現在5/9)

[実践Rust入門[言語仕様から開発手法まで] 単行本（ソフトカバー） – 2019/5/8](https://amzn.to/2VdAQ6y)

<a href="https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5Rust%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E9%96%8B%E7%99%BA%E6%89%8B%E6%B3%95%E3%81%BE%E3%81%A7-%CE%BAeen/dp/4297105594/ref=as_li_ss_il?_encoding=UTF8&psc=1&refRID=KADG0R1CJZD9Y07B3P7E&linkCode=li2&tag=peace098beat-22&linkId=52fef8a307968a1010a3375899274077&language=ja_JP" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4297105594&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=peace098beat-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=peace098beat-22&language=ja_JP&l=li2&o=9&a=4297105594" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

※アフェっときます