Halo teman-teman semuanya, pada artikel sebelumnya kita sudah membahas tentang closure di Rust. Kita melihat bagaimana closure bisa digunakan sebagai fungsi anonim yang fleksibel, bisa menangkap variabel dari lingkup luar, dan sering dipakai bersama iterator untuk membuat kode lebih ekspresif.
Pada artikel kali ini, kita akan membahas topik yang sangat menarik sekaligus menantang, yaitu concurrency di Rust. Concurrency adalah kemampuan untuk menjalankan beberapa tugas secara bersamaan, sehingga program bisa lebih efisien dan responsif. Contoh sederhana adalah ketika kita ingin membaca file, mengunduh data dari internet, dan memproses input pengguna pada saat yang sama.
Rust dirancang dengan filosofi fearless concurrency: kita bisa menulis program yang berjalan paralel dengan aman, tanpa khawatir dengan bug berbahaya seperti data race. Semua itu berkat sistem ownership dan borrowing yang sudah kita pelajari di bab sebelumnya.
Mari kita lihat beberapa cara concurrency di Rust: thread, channel, dan async/await.
Thread
Rust menyediakan fungsi std::thread::spawn
untuk membuat thread baru.
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..5 {
println!("Hello dari thread lain: {}", i);
thread::sleep(Duration::from_millis(500));
}
});
for i in 1..5 {
println!("Hello dari main thread: {}", i);
thread::sleep(Duration::from_millis(500));
}
handle.join().unwrap(); // tunggu thread selesai
}
Program ini akan menjalankan dua thread sekaligus: thread utama dan thread baru.
Channel
Untuk komunikasi antar-thread, Rust menyediakan channel. Channel terdiri dari sender dan receiver.
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let pesan = String::from("Halo dari thread!");
tx.send(pesan).unwrap();
});
let diterima = rx.recv().unwrap();
println!("Pesan diterima: {}", diterima);
}
Dengan channel, kita bisa mengirim data dari satu thread ke thread lain dengan aman.
Shared State dengan Mutex
Kadang kita ingin beberapa thread berbagi data. Rust menyediakan Mutex
(mutual exclusion) untuk memastikan hanya satu thread yang bisa mengakses data pada satu waktu.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..5 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
println!("Hasil counter: {}", *counter.lock().unwrap());
}
Di sini kita menggunakan Arc
(atomic reference counting) agar Mutex
bisa dibagikan ke beberapa thread.
Async / Await
Selain concurrency dengan thread, Rust juga mendukung asynchronous programming menggunakan async
dan await
. Namun, untuk runtime biasanya kita menggunakan crate seperti tokio
atau async-std
.
Contoh sederhana dengan tokio
:
// Tambahkan di Cargo.toml:
// tokio = { version = "1", features = ["full"] }
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let t1 = async {
sleep(Duration::from_secs(1)).await;
println!("Tugas 1 selesai");
};
let t2 = async {
sleep(Duration::from_secs(2)).await;
println!("Tugas 2 selesai");
};
tokio::join!(t1, t2);
println!("Semua tugas selesai");
}
Dengan async/await, kita bisa menjalankan beberapa tugas secara bersamaan dengan cara yang efisien.
Kesimpulan
Pada artikel ini kita sudah mempelajari dasar-dasar concurrency di Rust. Kita melihat bagaimana membuat thread dengan thread::spawn
, bagaimana komunikasi antar-thread menggunakan channel, bagaimana berbagi state dengan Mutex
dan Arc
, serta bagaimana asynchronous programming dengan async/await
.
Rust menjanjikan fearless concurrency, artinya kita bisa menulis program paralel dengan aman tanpa takut error yang berbahaya. Dengan memahami topik ini, kita sudah menyelesaikan seri Belajar Rust Dasar dari awal sampai konsep lanjutan.
Terima Kasih