Rustの並行処理|スレッドの作成とチャネル通信

先生

Rustで並行処理?スレッドとチャネルを使えば、安全で高速なプログラムが書けるんだ!🚀

Rustの並行処理:スレッドとチャネルで安全な並行プログラミング

Rustは、安全で効率的な並行処理を可能にする強力な機能を備えています。この記事では、Rustにおける並行処理の基本であるスレッドの作成とチャネル通信について、具体的なコード例を交えながら解説します。

並行処理を理解することで、複数のタスクを同時に実行し、プログラムのパフォーマンスを大幅に向上させることができます。Rustの所有権システムと借用チェッカーは、データ競合などの並行処理における一般的な問題をコンパイル時に検出するため、より安全な並行プログラミングを実現できます。

スレッドの作成

Rustで新しいスレッドを作成するには、std::threadモジュールのspawn関数を使用します。

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

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("spawned thread: {}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("main thread: {}", i);
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().unwrap();
}

thread::spawn関数は、クロージャを受け取り、新しいスレッドでそのクロージャを実行します。handle.join().unwrap()は、新しいスレッドが完了するまでメインスレッドをブロックします。これにより、スレッドが終了する前にメイン関数が終了するのを防ぎます。

スレッドを生成する際には、moveキーワードを使用して、クロージャが所有権を奪う必要がある変数を明示的に示すことができます。これにより、所有権の問題をコンパイル時に解決できます。

use std::thread;

fn main() {
    let message = String::from("Hello from main!");

    let handle = thread::spawn(move || {
        println!("Thread received: {}", message);
    });

    handle.join().unwrap();
}

チャネル通信

チャネルは、スレッド間でデータを安全に送受信するための機構です。Rustでは、std::sync::mpscモジュールを使ってチャネルを実装します(mpscはmultiple producer, single consumerの略)。

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("Hello from thread!");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}

mpsc::channel()関数は、送信者(tx)と受信者(rx)のペアを返します。送信者はsendメソッドを使ってデータをチャネルに送信し、受信者はrecvメソッドを使ってデータを受信します。recvメソッドは、データが利用可能になるまでブロックします。

複数のスレッドがデータを送信できるチャネルを作成することも可能です。

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    for i in 0..3 {
        let tx_clone = tx.clone();
        thread::spawn(move || {
            let val = format!("Message from thread {}", i);
            tx_clone.send(val).unwrap();
        });
    }

    drop(tx); // Close the original sender.

    for received in rx {
        println!("Got: {}", received);
    }
}

参考リンク

まとめ

Rustの並行処理は、スレッドとチャネルを使用することで、安全かつ効率的に実装できます。所有権システムと借用チェッカーが、データ競合などの問題をコンパイル時に検出するため、信頼性の高い並行プログラムを開発できます。スレッドの作成にはthread::spawnを使用し、スレッド間の通信にはstd::sync::mpscモジュールのチャネルを使用します。これらの機能を理解することで、Rustで高性能な並行アプリケーションを構築することが可能になります。