0Pricing
Learn Rust Coding · Pelajaran

Thread Berscope

Meminjam lintas-thread

Thread Berscope adalah pelajaran Learn Rust Coding gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Learn Rust Coding, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Learn Rust Coding mencakup 4 pelajaran total.

Masalah Peminjaman dalam Utas

Penutupan thread::spawn biasa harus bersifat 'static: penutupan tersebut tidak dapat meminjam variabel lokal, karena utas mungkin hidup lebih lama daripada fungsi yang memilikinya. Itulah sebabnya Anda sering melihat move dan Arc.

Utas berskop mengatasi hal ini dengan menjamin bahwa setiap utas selesai sebelum cakupan berakhir, sehingga peminjaman data lokal menjadi aman.

Mengapa spawn Memerlukan 'static

Dengan thread::spawn, utas yang dijalankan dapat terus berjalan setelah main atau fungsi apa pun selesai. Jika utas tersebut meminjam variabel lokal, variabel itu dapat dihancurkan saat masih digunakan oleh utas. Rust melarang hal ini saat kompilasi, sehingga Anda harus memindahkan data yang dimiliki ke dalam penutupan.

use std::thread;

fn main() {
    let nums = vec![1, 2, 3];
    // move transfers ownership into the thread
    let handle = thread::spawn(move || {
        println!("in thread: {:?}", nums);
    });
    handle.join().unwrap();
}

Memperkenalkan thread::scope

Yang distabilkan dalam Rust 1.63, std::thread::scope membuat cakupan tempat utas dapat meminjam variabel lokal. Cakupan tersebut menunggu hingga semua utas di dalamnya selesai, sehingga peminjaman tidak mungkin menjadi referensi yang menggantung.

Anda menjalankan utas dengan s.spawn(...) menggunakan pegangan cakupan s, bukan thread::spawn.

use std::thread;

fn main() {
    let data = vec![10, 20, 30];
    thread::scope(|s| {
        s.spawn(|| {
            println!("borrowed: {:?}", data);
        });
    });
    // data is still usable here
    println!("after scope: {:?}", data);
}

Meminjam Tanpa move

Di dalam thread::scope, Anda dapat membaca variabel lokal berdasarkan referensi tanpa move. Beberapa utas berskop dapat berbagi peminjaman tak dapat diubah dari data yang sama secara bersamaan, seperti referensi biasa.

use std::thread;

fn main() {
    let message = String::from("shared text");
    thread::scope(|s| {
        s.spawn(|| println!("thread 1 sees: {}", message));
        s.spawn(|| println!("thread 2 sees: {}", message));
    });
    println!("main still owns: {}", message);
}

Membagi Pekerjaan di Sepotong Larik

Pola yang umum adalah membagi sepotong larik dan meminta setiap utas memproses satu bagian. Utas berskop membuatnya rapi karena setiap utas dapat langsung meminjam sebagian dari sepotong larik asli tanpa perlu menggandakannya.

use std::thread;

fn main() {
    let numbers = [1, 2, 3, 4, 5, 6];
    let (left, right) = numbers.split_at(3);
    thread::scope(|s| {
        s.spawn(|| {
            let sum: i32 = left.iter().sum();
            println!("left sum:  {}", sum);
        });
        s.spawn(|| {
            let sum: i32 = right.iter().sum();
            println!("right sum: {}", sum);
        });
    });
}

Mengumpulkan Nilai Kembalian

Seperti utas biasa, s.spawn mengembalikan ScopedJoinHandle. Panggil .join() untuk mendapatkan nilai kembalian utas. Anda dapat mengumpulkan pegangan dan menggabungkannya setelah menjalankan semua utas untuk mengumpulkan hasil.

use std::thread;

fn main() {
    let inputs = [2, 4, 6];
    let mut handles = vec![];
    thread::scope(|s| {
        for &x in &inputs {
            handles.push(s.spawn(move || x * x));
        }
        let results: Vec<i32> = handles.into_iter()
            .map(|h| h.join().unwrap())
            .collect();
        println!("{:?}", results);
    });
}

Peminjaman yang Dapat Diubah Memerlukan Kehati-hatian

Dua utas berskop tidak dapat memegang peminjaman yang dapat diubah dari data yang sama secara bersamaan; hal itu akan melanggar aturan alias Rust. Untuk mengubah data bersama dari beberapa utas, Anda tetap memerlukan Mutex, tetapi satu utas dapat mengambil peminjaman unik yang dapat diubah dari bagian-bagian yang saling terpisah.

Di bawah ini, setiap utas mengubah separuh larik yang berbeda melalui split_at_mut.

use std::thread;

fn main() {
    let mut data = [1, 2, 3, 4];
    let (a, b) = data.split_at_mut(2);
    thread::scope(|s| {
        s.spawn(|| { for x in a.iter_mut() { *x *= 10; } });
        s.spawn(|| { for x in b.iter_mut() { *x += 100; } });
    });
    println!("{:?}", data);
}

Cakupan Menggabungkan Utas Secara Otomatis

Anda tidak perlu memanggil join pada setiap utas berskop. Saat penutupan scope selesai, Rust secara otomatis menggabungkan semua utas yang belum digabungkan sebelum melanjutkan. Inilah alasan peminjaman dijamin tetap valid sepanjang masa hidup utas.

use std::thread;
use std::time::Duration;

fn main() {
    let label = String::from("task");
    thread::scope(|s| {
        s.spawn(|| {
            thread::sleep(Duration::from_millis(30));
            println!("{} done", label);
        });
        println!("spawned, scope will wait");
    });
    println!("all scoped threads finished");
}

Menggabungkan Cakupan dengan Perubahan Bersama

Ketika utas harus mengubah nilai yang sama, gabungkan utas berskop dengan Mutex. Anda tidak perlu menggunakan Arc karena cakupan sudah memungkinkan utas meminjam Mutex lokal secara langsung.

use std::sync::Mutex;
use std::thread;

fn main() {
    let counter = Mutex::new(0);
    thread::scope(|s| {
        for _ in 0..5 {
            s.spawn(|| {
                let mut n = counter.lock().unwrap();
                *n += 1;
            });
        }
    });
    println!("counter = {}", *counter.lock().unwrap());
}

Berskop atau Dijalaankan: Kapan Menggunakan yang Mana

Gunakan utas berskop ketika pekerjaan memiliki batas dan selesai dalam satu fungsi, serta Anda ingin meminjam data tumpukan tanpa Arc atau penggandaan.

Gunakan thread::spawn ketika utas harus hidup lebih lama daripada fungsi saat ini atau berjalan sepanjang masa hidup program. Utas berskop tidak dapat keluar dari cakupannya.

Contoh Map Paralel

Menggabungkan semuanya: sebuah map paralel kecil yang mengubah setiap elemen vektor dalam utasnya sendiri sambil meminjam masukan, lalu mengumpulkan hasil sesuai urutan.

use std::thread;

fn parallel_double(items: &[i32]) -> Vec<i32> {
    let mut handles = Vec::new();
    let mut out = Vec::new();
    thread::scope(|s| {
        for &x in items {
            handles.push(s.spawn(move || x * 2));
        }
        for h in handles {
            out.push(h.join().unwrap());
        }
    });
    out
}

fn main() {
    let nums = vec![1, 2, 3, 4];
    println!("{:?}", parallel_double(&nums));
}

Pemeriksaan Singkat

Uji pemahaman Anda tentang utas berskop.

Rangkuman

Anda telah mempelajari utas berskop:

  • thread::spawn memerlukan penutupan 'static; utas berskop tidak.
  • thread::scope memungkinkan utas meminjam variabel lokal dengan aman.
  • Cakupan menggabungkan semua utas secara otomatis sebelum kembali.
  • Berbagi data yang dapat diubah tetap memerlukan Mutex, tetapi tidak memerlukan Arc di dalam cakupan.
  • Gunakan utas berskop untuk paralelisme berbatas yang lokal pada fungsi.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Thread Berscope” gratis?

Ya — teks lengkap “Thread Berscope” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Learn Rust Coding, upgrade ke CoddyKit PRO. Kursus Learn Rust Coding mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Thread Berscope”?

Meminjam lintas-thread Kamu berlatih Learn Rust Coding dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Learn Rust Coding?

Tidak diperlukan pengalaman sebelumnya. Learn Rust Coding di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Thread Berscope” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Learn Rust Coding ini?

Ya. Setiap pelajaran Learn Rust Coding menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Kanal mpsc
  2. Berbagi State dengan Arc/Mutex
  3. Thread Berscope
  4. Kanal Crossbeam
← Kembali ke Learn Rust Coding