Tokio๋ก ํ์ผ์ ์ธ ๋ ๊ฐ์ฅ ๋จผ์ ์์์ผ ํ ์ฌ์ค์ด ์์ต๋๋ค.
์ด์์ฒด์ ์์ค์์ ์ผ๋ฐ ํ์ผ์ ์ฝ๊ธฐ์ ์ฐ๊ธฐ๋ ๋ณธ์ง์ ์ผ๋ก ๋ธ๋กํน ์์
์
๋๋ค.
๋คํธ์ํฌ ์์ผ์ epoll, kqueue, IOCP ๊ฐ์ ์ง์ง ๋น๋๊ธฐ ํต์ง ๋ฉ์ปค๋์ฆ์ OS๊ฐ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ์ผ๋ฐ ํ์ผ์๋ ๊ทธ๋ฐ ๊ฒ์ด ์์ต๋๋ค. ๊ทธ๋์ Tokio๋ ํ์ผ I/O๋ฅผ ์ง์ง ๋น๋๊ธฐ๋ก ๋ง๋ค์ง ์๊ณ , ๋ธ๋กํน ์ฝ๋๋ฅผ ๋ณ๋ ์ค๋ ๋๋ก ๊ฒฉ๋ฆฌํ๋ ๋ฐฉ์์ ํํฉ๋๋ค.
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
async fn example() -> std::io::Result<()> {
let mut file = File::create("my_file.txt").await?;
file.write_all(b"First line.\n").await?;
file.flush().await?;
Ok(())
}
์ด ์ฝ๋์ .await๊ฐ ๋ด๋ถ์์ ๋ฌด์์ ํ๋์ง ๋จ๊ณ๋ณ๋ก ์ดํด๋ด
๋๋ค.
tokio::fs์ ํจ์๋ค์ ๋ด๋ถ์ ์ผ๋ก std::fs์ ๋ธ๋กํน ์ฝ๋๋ฅผ spawn_blocking์ผ๋ก ๋ณ๋ ์ค๋ ๋ ํ์ ๋์ง๋๋ค.
use std::fs::File;
use std::io::Write;
use tokio::task::spawn_blocking;
spawn_blocking(move || {
let mut file = File::create("my_file.txt")?;
file.write_all(b"First line.\n")?;
Ok::<(), std::io::Error>(())
}).await??;
tokio::fs::write๋ ์ด ํจํด์ ๊ทธ๋๋ก ๊ฐ์ผ ๊ฒ์
๋๋ค. ๋๋ฑํ ๋ธ๋กํน ์ฐ์ฐ์ spawn_blocking์ผ๋ก ๋ณ๋ ์ค๋ ๋ ํ์์ ์คํํฉ๋๋ค.
๋์ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
JoinHandle์ .await ํ๋คPoll::Pending์ผ๋ก ์ ๋ค๊ณ , executor๋ ๊ฐ์ ์ค๋ ๋์์ ๋ค๋ฅธ task๋ฅผ ์คํํ๋คWaker๋ฅผ ํธ์ถํด ์ ๋ task๋ฅผ ๊นจ์ด๋คJoinHandle์ด Poll::Ready๋ฅผ ๋ฐํํ๋ฉด .await๊ฐ ํด์๋๋คFuture, poll, Waker ๋ฉ์ปค๋์ฆ์ด ๊ทธ๋๋ก ์ฐ์ ๋๋ค. ๋ค๋ง ๊นจ์์ ์ผ์ผํค๋ ์ด๋ฒคํธ๊ฐ OS ์ด๋ฒคํธ๊ฐ ์๋๋ผ ๋ณ๋ ๋ธ๋กํน ์ค๋ ๋์ ์์ ์๋ฃ๋ผ๋ ์ ๋ง ๋ค๋ฆ ๋๋ค.
์ฌ๊ธฐ๊ฐ ์ง๊ด๊ณผ ์ด๊ธ๋๋ ๋ถ๋ถ์
๋๋ค.file.write_all(...).await๊ฐ ๋๋๋ ๋ฐ์ดํฐ๊ฐ ์ค์ ๋ก ํ์ผ์ ์ฐ์ธ ๊ฒ์ ์๋๋๋ค.
write ํธ์ถ์ ์ฐ๊ธฐ๊ฐ ๋๋๊ธฐ ์ ์ ๋ฐํ๋ฉ๋๋ค. write์ .await๋ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ถ ๋ฒํผ์ ๋ณต์ฌํ๊ณ ๋ธ๋กํน ์์
์ ์ ์ถํ ์์ ์ ๋ฐํ๋ฉ๋๋ค. ์ค์ ๋์คํฌ ์ฐ๊ธฐ๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ธ๋กํน ์ค๋ ๋๊ฐ ๋์ค์ ์ฒ๋ฆฌํฉ๋๋ค.
let mut file = File::create("my_file.txt").await?;
file.write_all(b"First line.\n").await?; // ๋ฒํผ์ ๋ณต์ฌ, ์์
์ ์ถ๋ง ๋๋จ
file.flush().await?; // ์ค์ ์ฐ๊ธฐ ์๋ฃ๋ฅผ ์ฌ๊ธฐ์ ๊ธฐ๋ค๋ฆผ
flush ์์ด ํจ์๊ฐ ๋๋๊ฑฐ๋ ํ์ผ์ด drop๋๋ฉด ์ฐ๊ธฐ ์์ฒด๋ ๊ฒฐ๊ตญ ์ผ์ด๋์ง๋ง, ์๋ฃ ์์ ์ด ๋ณด์ฅ๋์ง ์๊ณ ์๋ฌ๋ ํ์ธํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ Tokio File์ ์ธ ๋๋ flush๊ฐ ๋ฐ๋์ ํ์ํฉ๋๋ค. ์ด๊ฒ์ std::fs::File๊ณผ ๋ค๋ฅธ ์ ์ด๋ฉฐ, File์ด ๋ด๋ถ์ ์ผ๋ก spawn_blocking์ ์ฌ์ฉํ๋ค๋ ์ฌ์ค์์ ๋น๋กฏ๋ฉ๋๋ค.
spawn_blocking ํธ์ถ์๋ ๋น์ฉ์ด ์์ต๋๋ค.
๋ธ๋กํน ์ค๋ ๋๋ก์ ์๋ณต, ์ฆ ๋ฉ์์ง ์ ๋ฌ๊ณผ ๋ฒํผ ์ฒ๋ฆฌ ๋น์ฉ์ด ๋งค ํธ์ถ๋ง๋ค ๋ฐ์ํฉ๋๋ค.
์์ ์ฐ๊ธฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ํ๋ฉด spawn_blocking ํธ์ถ์ด ๊ทธ๋งํผ ๋์ด๋ฉ๋๋ค. ์ด๋ BufWriter๋ก ๊ฐ์ธ๋ฉด ์์ ์ฐ๊ธฐ๋ค์ด ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ์ ๋ชจ์ด๊ณ , ์ค์ write์ spawn_blocking ํธ์ถ์ flush ์์ ์ ํ ๋ฒ๋ง ์ผ์ด๋ฉ๋๋ค.
use tokio::fs::File;
use tokio::io::{AsyncWriteExt, BufWriter};
let mut file = BufWriter::new(File::create("my_file.txt").await?);
file.write_all(b"First line.\n").await?;
file.write_all(b"Second line.\n").await?;
file.write_all(b"Third line.\n").await?;
file.flush().await?; // ์ธ ๋ฒ์ ์ฐ๊ธฐ๊ฐ ํ ๋ฒ์ spawn_blocking์ผ๋ก ์ฒ๋ฆฌ๋จ
์ฐธ๊ณ ๋ก BufWriter ์์ด๋ Tokio์ File์ ์์ฒด ๋ด๋ถ ๋ฒํผ๋ฅผ ๊ฐ์ง๋๋ค. File::set_max_buf_size๊ฐ ๋จ์ผ spawn_blocking ํธ์ถ์์ ์ฝ๊ฑฐ๋ ์ฐ๋ ์ต๋ ๋ฐ์ดํธ ์๋ฅผ ์ ์ดํ๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ 2๋ฉ๊ฐ๋ฐ์ดํธ์
๋๋ค. ๊ทธ๋๋ ์์ ์ฐ๊ธฐ๋ฅผ ๋ช
์์ ์ผ๋ก ๋ฌถ์ผ๋ ค๋ฉด BufWriter๋ฅผ ์ฐ๋ ํธ์ด ํ์คํฉ๋๋ค.
๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ชจ์ ์ ์๋ค๋ฉด Vec<u8>๋ String์ ๋ชจ์์ tokio::fs::write๋ฅผ ํ ๋ฒ๋ง ํธ์ถํ๋ ๊ฒ์ด ๊ฐ์ฅ ๋จ์ํฉ๋๋ค.
let mut contents = String::new();
contents.push_str("First line.\n");
contents.push_str("Second line.\n");
contents.push_str("Third line.\n");
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
Tokio์ ํ์ผ I/O ์ฑ๋ฅ์ ์ข๊ฒ ํ๋ ค๋ฉด ์ฐ์ฐ์ ๊ฐ๋ฅํ ํ ์ ์ ์์ spawn_blocking ํธ์ถ๋ก ๋ฌถ๋ ๊ฒ์ด ํต์ฌ์
๋๋ค.
Tokio์ ํ์ผ ์ฐ๊ธฐ๋ ๋ธ๋กํน ์ฝ๋๋ฅผ ๋ณ๋ ์ค๋ ๋ ํ์ ์์ํ๊ณ , ๊ทธ๋์ ๋ฉ์ธ ์ค๋ ๋๋ ๋ค๋ฅธ ์ผ์ ํ๋ค๊ฐ, ์์
์ด ๋๋๋ฉด Waker๋ก ๊นจ์์ง๋ ๊ตฌ์กฐ์
๋๋ค.
write์ .await๋ ์ฐ๊ธฐ ์๋ฃ๊ฐ ์๋๋ผ ๋ฒํผ ๋ณต์ฌ์ ์์
์ ์ถ๊น์ง๋ง ๋ณด์ฅํ๋ฏ๋ก flush๊ฐ ๋ฐ๋์ ํ์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ spawn_blocking ํธ์ถ ํ์๋ฅผ ์ค์ด๋ ๊ฒ์ด ์ฑ๋ฅ์ ๊ด๊ฑด์ด๋ฏ๋ก, ์์ ์ฐ๊ธฐ๋ BufWriter๋ก ๋ฌถ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ๋ชจ์ ํ ๋ฒ์ ์ฐ๋ ๊ฒ์ด ์ข์ต๋๋ค.