第9章: Rustの並行性と非同期処理

並行処理や非同期処理は、アプリケーションが同時に複数のタスクを処理するための方法で、Rustでは効率的かつ安全に実行できる設計がされています。Rustは所有権モデルにより、メモリ管理やスレッドセーフティをコンパイル時に保証するため、並行処理や非同期処理においても他の言語と比べてバグが少なくなりやすい特徴があります。

この章では、Rustにおけるスレッド管理と非同期処理について詳しく解説します。具体的には、スレッドの基本的な使い方から、async/awaitによる非同期プログラミングの書き方までを網羅的に学びます。


9.1 Rustにおけるスレッド管理

Rustでは、標準ライブラリが提供するstd::threadモジュールを使ってスレッドを生成し、並行処理を行えます。スレッドはオペレーティングシステムの中で軽量な実行単位として扱われ、複数のスレッドを作成することで、プログラムは複数のタスクを並行して処理できます。

スレッドの基本的な作成

まず、Rustでスレッドを作成する基本的な方法を見ていきましょう。スレッドの作成には、thread::spawn関数を使用します。この関数は、新しいスレッドで実行したいクロージャ(無名関数)を受け取ります。

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

fn main() {
// 新しいスレッドを生成
let handle = thread::spawn(|| {
for i in 1..10 {
println!("新しいスレッド: {}", i);
thread::sleep(Duration::from_millis(1));
}
});

// メインスレッドでの処理
for i in 1..5 {
println!("メインスレッド: {}", i);
thread::sleep(Duration::from_millis(1));
}

// 新しいスレッドの終了を待つ
handle.join().unwrap();
}

上記の例では、thread::spawnで新しいスレッドを作成し、その中でループを実行しています。また、メインスレッドでは異なるループが実行され、並行して動作します。joinメソッドを使って、新しいスレッドが終了するまでメインスレッドが待機するようにしています。

スレッド間のデータ共有

スレッド間でデータを共有する場合、データ競合が発生しないように注意が必要です。Rustでは、スレッド間の安全なデータ共有を行うためにMutex(ミューテックス)やArc(アトミック参照カウント型)を使用します。

以下は、複数のスレッドでカウンタを共有する例です。

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}

for handle in handles {
handle.join().unwrap();
}

println!("結果: {}", *counter.lock().unwrap());
}

ここでは、ArcMutexを組み合わせて使用することで、複数のスレッドから安全にカウンタにアクセスできるようにしています。Arcはスレッド間でデータを共有するためのスマートポインタで、Mutexは排他制御を行い、データへのアクセスが他のスレッドと競合しないようにします。


9.2 非同期処理とasync/await

スレッドとは別に、Rustでは非同期処理を実現するためにasync/await構文が導入されています。非同期処理は、特定のタスクが終了するのを待たずに他のタスクを進めることができるため、リソースを効率的に活用できます。例えば、I/O待機中に他の処理を行うことで、スループットの向上が図れます。

非同期関数の定義

Rustで非同期処理を行うには、関数やブロックにasyncキーワードを付けます。以下は、非同期関数の基本的な定義方法です。

async fn say_hello() {
println!("Hello, world!");
}

このsay_hello関数は非同期関数であり、呼び出し元に制御を戻すことなく即座に完了します。しかし、この関数を実行するには、「実行器(Executor)」と呼ばれるランタイムが必要です。

非同期関数の実行

非同期関数を実行するためには、awaitを使用してその結果を待つか、実行器で関数を実行します。以下のコードは、async/awaitの基本的な使用方法を示しています。

use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
let task1 = async {
for i in 1..5 {
println!("タスク 1 - カウント: {}", i);
sleep(Duration::from_millis(500)).await;
}
};

let task2 = async {
for i in 1..5 {
println!("タスク 2 - カウント: {}", i);
sleep(Duration::from_millis(500)).await;
}
};

tokio::join!(task1, task2);
}

この例では、tokio::join!マクロを使って、task1task2を同時に実行しています。sleep関数を使用して500ミリ秒の遅延を導入しており、それぞれのタスクが並行して進行することがわかります。

非同期処理の実例: HTTPリクエストの実行

以下は、非同期処理を用いて複数のHTTPリクエストを並行して実行する例です。ここでは、reqwestクレートを使用して、複数のURLに非同期でアクセスしています。

use reqwest::Error;
use tokio::task;

async fn fetch_url(url: &str) -> Result<String, Error> {
let response = reqwest::get(url).await?;
let body = response.text().await?;
Ok(body)
}

#[tokio::main]
async fn main() {
let urls = vec![
"https://example.com",
"https://example.org",
"https://example.net",
];

let fetches = urls.into_iter().map(|url| {
task::spawn(async move {
match fetch_url(url).await {
Ok(content) => println!("Fetched content from {}: {}", url, &content[0..50]),
Err(e) => println!("Error fetching {}: {}", url, e),
}
})
});

for fetch in fetches {
fetch.await.unwrap();
}
}

ここでは、task::spawnを使用して、各URLに非同期でリクエストを送り、その結果を並行して処理しています。この方法により、I/O待機時間を効率的に活用し、複数のリクエストを同時に処理することができます。


9.3 並行性と非同期処理の選択

Rustでは、並行処理にスレッドを使うか非同期処理を使うかの選択肢があります。次のような基準で選ぶのが良いでしょう。

  1. スレッド: CPUバウンドな処理が多く、各タスクが独立している場合。
  2. 非同期処理: I/Oバウンドな処理が多く、待機時間が発生する場合。

両者を理解し、適切な場面で使い分けることで、Rustでより効率的なプログラムを構築できます。


初心者におすすめ!プログラミングスクールのススメ

未経験でも気軽に!サブスク型プログラミングスクール【Freeks】

プログラミングを始めたいと思っているそこのあなた、独学よりもプログラミングスクールが断然おすすめです!理由は簡単、続けやすさです。

独学の挫折率、驚きの87.5%!

独学でプログラミングを続けるのは、実はかなりハードルが高いんです。データによると、なんと87.5%もの学習者が途中で挫折しているとか。一方、各プログラミングスクールが公表しているデータによると、受講生の約95%が最後までやり抜いているとのこと。数字を見れば一目瞭然、プログラミングスクールの方が圧倒的に続けやすいんです。

有料と無料、スクールの違いは?

プログラミングスクールには有料と無料のタイプがありますが、その違いは次の通りです:

  • 受講条件が異なる
  • 学べるスキルやカリキュラム内容が異なる
  • 就職や転職のサポート内容が異なる

どちらが自分に合っているか、よく考えて選ぶのが大事です。

サブスク型プログラミングスクール『FREEKS(フリークス)』に注目!

プログラミング初心者でも学びやすいと評判の『FREEKS』、その特徴は以下の通り:

  • 未経験者向けのわかりやすいカリキュラム
  • 経験豊富なエンジニアのサポート
  • オンラインで自分のペースで学習可能

なんと、月会費のみで全カリキュラムが受け放題!Java、PHP、HTML/CSS、JavaScriptなど、多彩なプログラミング言語が学べるんです。しかも、AIが質問に自動で答えてくれるシステムも導入済み。

終了後は副業もサポート!

カリキュラムを終了した後には、Freeks経由で未経験者でも取り組める副業案件の受注が可能。実務を通じてスキルを磨き、市場価値の高いエンジニアへの道が開けます。

独学で悩むくらいなら、まずはプログラミングスクールをチェックしてみるのもアリかもしれませんよ!
 ↓ ↓ こちらをクリック ↓ ↓ 

p-school

Recent Posts

第6章: PHPのデータベース操作

PHPを使用してデータベースに…

2週間 ago

第5章: PHPのオブジェクト指向プログラミング(OOP)

オブジェクト指向プログラミング…

2週間 ago

第4章: PHPの関数

プログラミングにおいて、関数は…

2週間 ago

第3章: PHPの配列とコレクション

PHPでの配列とコレクションの…

2週間 ago

第2章: PHPの基本文法

PHPの基本的な構文や使い方を…

2週間 ago