Menjalankan Kode Secara Simultan
Versi Bahasa Indonesia. Baca dalam Bahasa Inggris
- Rust menyediakan dukungan bawaan untuk pemrograman konkuren melalui modul standard library
std::thread. - Thread di Rust memungkinkan beberapa bagian program untuk dieksekusi secara simultan, memanfaatkan prosesor multi-core.
Threads
-
Anda dapat membuat thread menggunakan
std::thread::spawn, yang menerima sebuah closure, menjalankannya di thread baru, dan mengembalikanJoinHandle. -
Kita dapat menunggu thread yang dibuat selesai menggunakan method
joindariJoinHandleyang dikembalikan.pub fn join(self) -> Result<T>: Menunggu thread yang terkait selesai. Fungsi ini akan kembali segera jika thread yang terkait sudah selesai. -
Kita sering menggunakan kata kunci
movedengan closure yang diteruskan kethread::spawnkarena closure tersebut kemudian akan mengambil kepemilikan nilai yang digunakannya dari environment, sehingga mentransfer kepemilikan nilai-nilai tersebut dari satu thread ke thread lain.
Contoh
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread!");
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {i} from the main thread!");
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}Menggunakan Smart Pointers, Mutex, dan Channels dalam Threads
Shared Mutable State dengan Arc dan Mutex
Dalam program multi-threaded, jika kita membutuhkan shared mutable state, kita dapat menggunakan:
Arc<T>:- Sebuah atomic reference-counted smart pointer untuk shared ownership di seluruh thread.
Mutex<T>:- Sebuah primitive sinkronisasi untuk mutual exclusion agar dapat mengakses data bersama dengan aman.
lock(): Mengakuisisi lock. Memblokir thread jika lock sedang dipegang.try_lock(): Mencoba mengakuisisi lock segera. Jika lock tidak dapat diakuisisi, mengembalikanErr.
Contoh
use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
struct JobStatus {
jobs_done: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));
let mut handles = Vec::new();
for _ in 0..10 {
let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(250));
// lock dan update jobs_done
status_shared.lock().unwrap().jobs_done += 1
});
handles.push(handle);
}
// Menunggu semua pekerjaan selesai.
for handle in handles {
handle.join().unwrap();
}
println!("Jobs done: {}", status.lock().unwrap().jobs_done);
}Arc<T>: Memungkinkan shared ownership dariMutexdi seluruh thread.Mutex<T>: Memastikan hanya satu thread yang mengakses counter pada satu waktu.
Multiple Readers Single Writer
RwLock (singkatan dari Read-Write Lock) adalah primitive sinkronisasi yang memungkinkan multiple readers atau single writer untuk mengakses data bersama. Ini memastikan akses konkuren yang aman dalam lingkungan multi-threaded.
- Multiple Readers: Banyak thread dapat memegang read lock secara simultan jika tidak ada thread yang memegang write lock.
- Single Writer: Hanya satu thread yang dapat memegang write lock, dan ia memiliki akses eksklusif ke data.
RwLock adalah bagian dari modul std::sync dan sering digunakan ketika Anda ingin berbagi data di antara thread dengan operasi baca dan tulis sambil meminimalkan contention.
- Read Lock
read(): Mengakuisisi read lock. Memblokir thread jika write lock sedang dipegang. Mengembalikan immutable reference ke data.try_read(): Mencoba mengakuisisi read lock segera dan mengembalikanErrjika tidak dapat mengakuisisi read lock.
- Write Lock
write(): Mengakuisisi write lock. Memblokir thread jika ada read atau write lock yang dipegang. Mengembalikan mutable reference ke data.try_write(): Mencoba mengakuisisi write lock segera dan mengembalikanErrjika tidak dapat mengakuisisi write lock.
Contoh
use std::{
sync::{Arc, RwLock},
thread,
time::Duration,
};
struct JobStatus {
jobs_done: u32,
}
fn main() {
let status = Arc::new(RwLock::new(JobStatus { jobs_done: 0 }));
let mut handles = Vec::new();
// Write jobs
for _ in 0..10 {
let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(250));
// write lock dan update jobs_done
status_shared.write().unwrap().jobs_done += 1
});
handles.push(handle);
}
// Read jobs
for _ in 0..10 {
let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(250));
// read lock dan dapatkan jobs_done
println!("Jobs done: {}", status_shared.read().unwrap().jobs_done);
});
handles.push(handle);
}
// Menunggu semua pekerjaan selesai.
for handle in handles {
handle.join().unwrap();
}
}- Counter dibungkus dalam
Arc<RwLock<T>>sehingga dapat dibagikan dengan aman antar thread. Arcmenyediakan reference counting untuk thread-safe ownership.write(): Mengakuisisi write lock, memberikan akses mutable eksklusif ke shared counter.read(): Mengakuisisi read lock, memungkinkan banyak thread mengakses counter secara immutable.- Lock memastikan bahwa data races dicegah saat mengakses shared counter.
Komunikasi Antar Thread dengan Channels
Rust menyediakan channels untuk komunikasi thread di modul std::sync::mpsc:
mpsc: Singkatan dari multiple producers, single consumer.- Itu berarti kita dapat membuat banyak
Sendermenggunakan methodclone.
Contoh
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel(); // Buat sebuah channel
// clone Sender
let txc = tx.clone();
// Buat thread untuk mengirim pesan
thread::spawn(move || {
let messages = vec![1, 2, 3, 4, 5];
for msg in messages {
txc.send(msg).unwrap(); // Kirim pesan
thread::sleep(Duration::from_millis(100));
}
});
// Buat thread untuk mengirim pesan
thread::spawn(move || {
let messages = vec![6, 7, 8, 9, 10];
for msg in messages {
tx.send(msg).unwrap(); // Kirim pesan
thread::sleep(Duration::from_millis(100));
}
});
// Terima pesan di thread utama
for received in rx {
println!("Received: {}", received);
}
}mpsc::channelmembuat sebuah transmitter (tx) dan sebuah receiver (rx).- Pesan dikirim melalui Sender
txdan diterima melalui Receiverrx.
Best Practices untuk Multithreading
- Minimalkan Lock Contention:
- Jaga critical section (di mana mutex di-lock) sesingkat mungkin untuk menghindari memperlambat thread.
- Gunakan
ArcdanMutexdengan Bijak:- Hindari menggunakan shared state kecuali diperlukan.
- Lebih suka message passing dengan channels untuk isolasi yang lebih baik.
Referensi
- https://doc.rust-lang.org/book/ch16-00-concurrency.html
- https://doc.rust-lang.org/book/ch16-01-threads.html
- https://doc.rust-lang.org/book/ch16-02-message-passing.html
- https://doc.rust-lang.org/book/ch16-03-shared-state.html
Last updated on