เรามาทำความรู้จักกับ Tokio กันดีกว่า ว่ามันคืออะไร ถ้าเราดูจาก Overview ในเว็บของ Tokio แบบเร็วๆ จะเห็นว่า ตัว Tokio นั้นเป็น Library สำหรับช่วยในการเขียน Concurrency Programming ด้วยรูปแบบ Async/Await ใน Rust นั่นเอง
แต่เดี๋ยวก่อน Tokio นั้น ไม่ใช้ Async/Await แบบปกตินะ แถมมันยังเป็น Multi-Threaded Runtime อีกด้วย
สมมติว่าเรามี code
ทีนี้ถ้าเราอยากเปลี่ยน Code เดิมของเราให้เปลี่ยนไปใช้ Tokio อันดับแรกก็ให้ไปที่ cargo.toml แล้วเพิ่ม Tokio เข้าไปแบบนี้
[package]
name = "threads-poc"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }cargo.toml
เติม async ที่หน้า fn handle_connection() แบบนี้
async fn handle_connection(mut stream: TcpStream) {
//...
}main.rs
จากนั้นทำการแก้ code ที่ fn main() ใน File main.rs แบบนี้
#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:80").unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
tokio::spawn(handle_connection(stream));
}
}main.rs
โดย #[tokio::main] นั้นเป็น Macro ที่ทำหน้าที่แปลง async fn main() ให้เป็น fn main() แบบ Synchronous บน Runtime
เพราะว่าปกติแล้วใน Tokio ถ้าหากเราไม่ได้ประกาศ fn main() ให้เป็น async fn main() มันจะไม่สามารถ Call Function อะไรก็ตามที่เป็น async fn แล้วเราต้องการ .await เพื่อ Return ได้เลย ยกตัวอย่างเช่น ให้ลองแก้ Code ที่ fn main() ให้เป็นแบบนี้ดูครับ
async fn main() {
let listener = TcpListener::bind("127.0.0.1:80").unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
handle_connection(stream).await;
}
}main.rs
ลอง run ดู จะเห็นว่ามันเกิด Error ขึ้น
แล้วก็อย่าลืมเปลี่ยน Code กลับเป็นแบบก่อนหน้าด้วยล่ะ
ลองทำการ Start Project แล้วสังเกตุดู เริ่มต้นมาจะเห็นว่ามันไปจอง Threads ถึง 13 Threads เลยทีเดียว (จำนวน Threads ของแต่ละคนอาจจะไม่เท่ากัน)
เราควรนำ Tokio ไปใช้ตอนไหน ?
แล้วถ้ามันเก่งเจ๋งขนาดนี้ทำไมเราไม่ใช้ Tokio แทน Threads ที่เป็น Built-In ของ Rust ไปเลย
เราลอง Weight ดูกับ Usecase ของเราก่อนว่าสิ่งที่เราต้องการทำกับ Tokio ที่เราจะดึงมันมาใช้ มันตรงกันหรือไม่ ซึ่ง Usecases ที่มันไม่เหมาะกับ Tokio ได้แก่
- การเอา Tokio ไปใช้คำนวณอะไรเยอะๆ ที่เน้น CPU เป็นหลัก เพราะมันไม่ได้ช่วยให้ Performance ของการคำนวณเพิ่มขึ้นแต่อย่างใด เนื่องจาก Tokio เขา Design มาเพื่อตอบโจทย์การเอาไปใช้ทำ I/O มากกว่า
- เอาไปใช้ Read/Write Files จำนวนมาก เนื่องจากว่า Tokio มันเป็น Library ที่อยู่ On-Top ของ OS อีกที ทำให้การ นำ Tokio ไปใช้กับ งานที่ Read/Write Files แบบเยอะๆ ไม่ได้ส่งผลให้ Performance ดีขึ้น เพราะสุดท้ายมันก็ขึ้นอยู่กับ OS อยู่ดีว่าจะ Handle การ Read/Write ของ Files ยังไง
- เอาไปทำ Single Web Request เพราะว่าถ้าจะทำ Single Web Request เราก็กลับไปใช้ Single Thread ปกติก็ได้
ก็ประมาณนี้ครับสำหรับตัวอย่าง Usecase ที่ไม่เหมาะกับการที่เราจะนำ Tokio ไปใช้งาน