Concurrency (Rust)
- ๋์์ฑ: ํ๋ก๊ทธ๋จ์ ์๋ก ๋ค๋ฅธ ์ผ๋ถ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ์คํํ๋ ๊ฒ.
- ๋ณ๋ ฌ์ฑ: ํ๋ก๊ทธ๋จ์ ์๋ก ๋ค๋ฅธ ์ผ๋ถ๋ฅผ ๊ฐ์ ์์ ์ ์คํํ๋ ๊ฒ.
Thread
- ๋ง์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๊ฐ ์์ฒด์ ์ผ๋ก ํน๋ณํ ์ค๋ ๋ ๊ตฌํ์ ์ ๊ณตํ๋ค:
- ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๊ฐ ์ ๊ณตํ๋ ์ค๋ ๋๋ฅผ ๊ทธ๋ฆฐ ์ค๋ ๋(green thread)๋ผ๊ณ ๋ ํ๋ฉฐ, ์๋ก ๋ค๋ฅธ ์์ OS ์ค๋ ๋๋ก ์คํ๋๋ค.
- ๊ทธ๋ฆฐ ์ค๋ ๋ ๋ชจ๋ธ์ M:N ๋ชจ๋ธ์ด๋ผ๊ณ ๋ ํ๋ค:
N
๊ฐ์ OS ์ค๋ ๋ ๋นM
๊ฐ์ ๊ทธ๋ฆฐ ์ค๋ ๋๊ฐ ํ ๋น๋๋ค.
- ๋ฌ์คํธ๋ ์ ์์ค ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ด๋ฏ๋ก ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ 1:1 ์ค๋ ๋ฉ๋ง ์ ๊ณตํ๋ค.
thread::spawn
ํจ์๋ฅผ ํตํด ์ค๋ ๋๋ฅผ ๋ง๋ค ์ ์๋ค:use std::thread; use std::time::Duration; fn main() { thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } }
hi number 1 from the main thread! hi number 1 from the spawned thread! hi number 2 from the main thread! hi number 2 from the spawned thread! hi number 3 from the main thread! hi number 3 from the spawned thread! hi number 4 from the main thread! hi number 4 from the spawned thread! hi number 5 from the spawned thread!
- ์์ง ์คํฐ๋ ์ค๋ ๋์ ์์ ์ด ๋๋์ง ์์๋๋ฐ๋ ๋ฉ์ธ ์ค๋ ๋ ์์ ์ด ๋๋๋ ๋ฐ๋์ ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋์ด ๋ฒ๋ ธ๋ค.
thread::spawn
ํจ์๊ฐ ๋ฐํํ๋JoinHandle
์join
๋ฉ์๋๋ ์ค๋ ๋๊ฐ ๋๋ ๋๊น์ง ๋๊ธฐํ๊ฒ ๋ง๋ ๋ค:use std::thread; use std::time::Duration; fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } handle.join().unwrap(); }
- ์ค๋ ๋ ํด๋ก์ ์์์ ๋ฉ์ธ ์ค๋ ๋์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ค๋์ญ์ ์ด๋์์ผ์ผ ํ๋ค:
- ๊ทธ๋ ์ง ์์ผ๋ฉด ์ค๋ ๋์์ ์ฐธ์กฐํ๊ณ ์๋ ๋ฐ์ดํฐ๊ฐ ๋ฉ์ธ ์ค๋ ๋์์ ๋๋กญ๋๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค:
use std::thread; fn main() { let v = vec![1, 2, 3]; let handle = thread::spawn(|| { println!("Here's a vector: {:?}", v); }); drop(v); // oh no! handle.join().unwrap(); }
- ํด๋ก์ ์์
move
ํค์๋๋ฅผ ๋ถ์ด๋ฉด ํด๋ก์ ๊ฐ ์ค๋์ญ์ ๊ฐ๊ฒ ๋๋ค: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(); }
- ์ด๋ ๊ฒ ํ๋ฉด ํด๋ก์ ๊ฐ
v
์ ๋ํ ์ค๋์ญ์ ๊ฐ๊ณ ์์ผ๋ฏ๋ก ๋ฉ์ธ ์ค๋ ๋์์v
๋ฅผ ๋๋กญํ ์ ์๋ค. - ๋ฌ์คํธ์ ์ค๋์ญ ๊ท์น์ด ๋ ์ฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ค.
- ์ด๋ ๊ฒ ํ๋ฉด ํด๋ก์ ๊ฐ
- ๊ทธ๋ ์ง ์์ผ๋ฉด ์ค๋ ๋์์ ์ฐธ์กฐํ๊ณ ์๋ ๋ฐ์ดํฐ๊ฐ ๋ฉ์ธ ์ค๋ ๋์์ ๋๋กญ๋๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค:
Async
- ์ค๋ ๋๋ ๋จ์ํ์ง๋ง, ๋๊ธฐํ๊ฐ ์ด๋ ต๊ณ ์ฑ๋ฅ ์ค๋ฒํค๋๋ ํฌ๋ค. ๋น๋๊ธฐ๋ ์ค๋ฒํค๋๊ฐ ์๋ค.
- ๋น๋๊ธฐ๊ฐ ์ค๋ ๋๋ณด๋ค ํญ์ ๋ ๋์ ๊ฒ์ ์๋๋ค. ๊ตณ์ด ๋น๋๊ธฐ์ ์ฑ๋ฅ์ด ํ์ํ๊ฒ ์๋๋ฉด ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋๊ฒ ๋ ์ฝ๋ค.
- ๋ฌ์คํธ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ธ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ ๋๊ตฌ๋ง ์ ๊ณตํ๋ค. ๋ฐ๋ผ์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค:
async
๋ ์ฝ๋ ๋ธ๋ก์Future
ํธ๋ ์์ ๊ตฌํํ๋ ์ํ ๋จธ์ ์ผ๋ก ๋ณํํ๋ค:async fn learn_and_sing() { // ๋ ธ๋๋ฅผ ๋ถ๋ฅด๊ธฐ ์ ์ ๊ทธ ๋ ธ๋๋ฅผ ๋ฐฐ์ธ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค. // ์ฌ๊ธฐ์ `block_on` ๋์ `.await`์ ์ฌ์ฉํจ์ผ๋ก์จ ์ค๋ ๋ ๋ธ๋กํน์ ๋ฐฉ์งํ๊ณ , // ๊ฐ์ ์์ ์ `dance`๋ฅผ ์คํํ ์ ์๋๋ก ํ๋ค. `.await`๋ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๋ ๋์ // future๊ฐ ์๋ฃ๋ ๋๊น์ง ๋น๋๊ธฐ์ ์ผ๋ก ๊ธฐ๋ค๋ฆฐ๋ค. let song = learn_song().await; sing_song(song).await; } async fn async_main() { let f1 = learn_and_sing(); let f2 = dance(); // `join!`์ `.await`์ ๋น์ทํ์ง๋ง ์ฌ๋ฌ futures๋ฅผ ๋์์ ๊ธฐ๋ค๋ฆฐ๋ค. // ๋ง์ฝ `learn_and_sing`๊ฐ ์ ์ ๋ธ๋กํน๋๋ฉด, `dance`๊ฐ ํ์ฌ ์ค๋ ๋๋ฅผ ์ ์ ํ ๊ฒ์ด๋ค. // ๋ง์ฝ `dance`๊ฐ ๋ธ๋กํน๋๋ฉด, `learn_and_sing`์ด ๋ค์ ์ค๋ ๋๋ฅผ ์ ์ ํ๋ค. // ๋ง์ฝ ๋ ๋ค ๋ธ๋กํน๋๋ฉด `async_main`์ด ๋ธ๋กํน๋๊ณ , ์คํ์์๊ฒ ์ค๋ ๋๋ฅผ ์๋ณดํ ๊ฒ์ด๋ค. // `let (book, music) = futures::join!(get_book, get_music);` ์ฒ๋ผ ํ์ด๋ฅผ ๋ฐํํ ์๋ ์๋ค. futures::join!(f1, f2); } fn main() { // `block_on`์ future๊ฐ ์๋ฃ๋ ๋๊น์ง ํ์ฌ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๋ค. block_on(async_main()); }
Future
Future
ํธ๋ ์์ ๋ฌ์คํธ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ.- ๋๋ต ์ด๋ ๊ฒ ์๊ฒผ๋ค:
trait SimpleFuture { type Output; fn poll(&mut self, wake: fn()) -> Poll<Self::Output>; } enum Poll<T> { Ready(T), Pending, }
poll
: future๊ฐ ์๋ฃ๋์ผ๋ฉดPoll::Ready(result)
๋ฅผ, ์๋๋ฉดPoll::Pending
์ ๋ฐํํ๋ค.Poll::Pending
๋ฐํ ํ future๊ฐ ๋ ์งํํ ์ค๋น๊ฐ ๋๋ฉดwake
ํจ์๋ฅผ ํธ์ถํ๋ค.wake
ํจ์๊ฐ ํธ์ถ๋๋ฉด ์คํ์๊ฐ ๋ค์poll
์ ํธ์ถํจ์ผ๋ก์จ future๋ฅผ ๋ ์งํ์ํจ๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ ์ฐจ์ด
- ์๋ฐ์คํฌ๋ฆฝํธ๋ async-first ์ธ์ด๋ค.
- ๋ ๊ฐ์ง ๋ฉด์์ ์๋ฐ์คํฌ๋ฆฝํธ์ promise์ ๋ฌ์คํธ์ futures๋ ๋ค๋ฅด๋ค:
- promise๋ ์์ฑ ์ฆ์ ์ค์ผ์ค๋๋ค. ๋ฐ๋ฉด, futures๋
await
๋์ ๋๋ง ์ค์ผ์ค๋๋ค. - ๋ชจ๋ promies๋ fallibleํ๋ค. ๋ฐ๋ฉด, futures๋ infallibleํ ์ ์๋ค.
- promise๋ ์์ฑ ์ฆ์ ์ค์ผ์ค๋๋ค. ๋ฐ๋ฉด, futures๋
์ฐธ๊ณ ์๋ฃ
- https://rust-lang.github.io/async-book/
- https://doc.rust-lang.org/book/ch16-00-concurrency.html
- https://tokio.rs/tokio/tutorial/hello-tokio
- https://blog.yoshuawuyts.com/futures-concurrency/