0Pricing
Learn Rust Coding · レッスン

Tokioで非同期アプリケーションを構築する

Tokioランタイムを使って非同期タスクを効率的に実行し、I/Oなどの並行処理を扱います。

「Tokioで非同期アプリケーションを構築する」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン2/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全3レッスンが含まれています。

Tokio ランタイムを見てみる

おかえりなさい!前のレッスンでは、async と await について学びました。しかし、async 関数は実際にはどのように実行されるのでしょうか。

そこで登場するのが、Tokio のような非同期ランタイムです。Tokio は、非同期 Rust コードを実行する環境を提供する強力なライブラリです。

  • Future をスケジュールして実行します。
  • ノンブロッキング I/O 操作を処理します。
  • 並行タスクを効率的に管理します。

非同期コードを実行する

Tokio を使い始めるには、通常 #[tokio::main] 属性マクロを使用します。このマクロは async fn main() を、Tokio ランタイムを初期化して非同期コードを実行する標準的な fn main() に変換します。

これは、非同期アプリケーションのエントリーポイントだと考えるとよいでしょう。

use tokio;

#[tokio::main]
async fn main() {
  println!("Hello from Tokio!");
}

新しい非同期タスクを生成する

Tokio の主要な機能の 1 つは、複数の非同期操作を並行して実行できることです。これには tokio::spawn を使用します。

tokio::spawn は Future を受け取り、Tokio ランタイム上で実行されるようスケジュールします。これにより、生成したタスクがバックグラウンドで実行されている間も、メインタスクは処理を続けられます。

  • ノンブロッキングで実行されます。
  • 完了を待機するための JoinHandle を返します。
  • タスクは独立して実行されます。

<code>tokio::spawn</code> の動作

tokio::spawn を使ってコードを並行実行する方法を見てみましょう。両方のメッセージが表示されますが、スリープ処理のため、「task complete」より先に「done」が表示される場合があることに注目してください。

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

#[tokio::main]
async fn main() {
  // Spawn a new task
  let handle = tokio::spawn(async {
    sleep(Duration::from_secs(1)).await;
    println!("Async task complete!");
  });

  println!("Main task continuing...");

  // Wait for the spawned task to finish
  handle.await.unwrap();
  println!("All tasks done.");
}

複数のタスクを待機する

複数のタスクがある場合、それらすべての完了を待つ必要が生じることがよくあります。Tokio には、この目的のために tokio::join! マクロが用意されています。

tokio::join! を使うと、複数の Future を並行して await し、その結果をまとめられます。複数の JoinHandle を `await` する方法に似ていますが、Future の数が固定されている場合は、より簡潔に書けることが多いです。

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

#[tokio::main]
async fn main() {
  let task1 = async {
    sleep(Duration::from_secs(1)).await;
    println!("Task 1 finished");
    1
  };

  let task2 = async {
    sleep(Duration::from_millis(500)).await;
    println!("Task 2 finished");
    2
  };

  let (result1, result2) = tokio::join!(task1, task2);
  println!("Results: {}, {}", result1, result2);
}

Tokio で非同期ファイル I/O

従来のファイル操作はスレッドをブロックする可能性があり、非同期アプリケーションには適していません。Tokio の tokio::fs モジュールは、ファイルシステム操作の非同期版を提供します。

これにより、I/O がノンブロッキングで処理されるため、大きなファイルを読み込んだり、多数のファイル操作を行ったりしている間も、アプリケーションの応答性を保てます。

  • tokio::fs::read_to_string
  • tokio::fs::write
  • より細かく制御するための tokio::fs::File

ファイルを非同期で読み込む

tokio::fs::read_to_string を使ってファイルを非同期で読み込む方法を見てみましょう。このコードを実行するには、Rust プロジェクトと同じディレクトリ(例:src/ 内またはプロジェクトのルート)に、内容を含む hello.txt という名前のファイルがあることを確認してください。

use tokio::fs;

#[tokio::main]
async fn main() {
  let path = "hello.txt";
  // Create a dummy file for the example if it doesn't exist
  // In a real app, you'd handle file creation/existence more robustly
  if let Err(_) = fs::metadata(path).await {
    fs::write(path, "Hello, Tokio file!").await.unwrap();
  }

  match fs::read_to_string(path).await {
    Ok(content) => println!("File content: '{}'", content),
    Err(e) => eprintln!("Error reading file: {}", e),
  }
}

非同期ネットワーク操作

Tokio はネットワークプログラミングで真価を発揮します。その tokio::net モジュールは、TCP および UDP 通信用のノンブロッキングな基本機能を提供します。

これは、多数の接続をそれぞれ専用スレッドなしで同時に処理できる、高性能なサーバーやクライアントを構築するうえで重要です。

  • サーバーには tokio::net::TcpListener を使用します。
  • クライアント接続には tokio::net::TcpStream を使用します。

非同期 TCP サーバーの基本構造

完全なサーバーは複雑ですが、このコード例では Tokio を使った非同期 TCP サーバーの中心的なループを示しています。受信接続を待ち受け、接続ごとにメッセージを表示します。実行したら、ブラウザーで http://127.0.0.1:8080 を開いて接続を確認してみてください。

use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
  let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
  println!("Listening on: {}", listener.local_addr().unwrap());

  loop {
    let (socket, addr) = listener.accept().await.unwrap();
    println!("Accepted connection from: {}", addr);
    // In a real server, you'd spawn a task to handle the socket
    // tokio::spawn(async move { handle_connection(socket).await; });
  }
}

// fn handle_connection(socket: TcpStream) { /* ... */ } // Placeholder

Tokio タスクチャレンジ

Tokio を使った次の Rust コードについて考えてみましょう。このプログラムを実行したとき、コンソールに最初に表示されるメッセージは何でしょうか。

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

#[tokio::main]
async fn main() {
  tokio::spawn(async {
    sleep(Duration::from_millis(200)).await;
    println!("Task 1: Done");
  });

  tokio::spawn(async {
    sleep(Duration::from_millis(100)).await;
    println!("Task 2: Done");
  });

  println!("Main: Starting tasks...");

  sleep(Duration::from_millis(300)).await;
  println!("Main: Finishing.");
}

復習:Tokio で構築する

Rust と Tokio を使った非同期アプリケーション構築への大きな一歩を踏み出しました。

  • Tokio は非同期ランタイムとして、async コードを実行します。
  • #[tokio::main] は、プログラムの非同期エントリーポイントです。
  • tokio::spawn を使うと、複数のタスクを並行して実行できます。
  • tokio::join! は、複数の Future の await に役立ちます。
  • Tokio は、ファイル(tokio::fs)とネットワーク(tokio::net)向けにノンブロッキング I/O を提供します。

これらのツールは、Rust で高い並行性と応答性を備えたアプリケーションを作成するための基本要素です。練習を続けてください。

よくある質問

「Tokioで非同期アプリケーションを構築する」レッスンは無料ですか?

はい。「Tokioで非同期アプリケーションを構築する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全3レッスンが含まれています。

「Tokioで非同期アプリケーションを構築する」で何を学びますか?

Tokioランタイムを使って非同期タスクを効率的に実行し、I/Oなどの並行処理を扱います。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Learn Rust Codingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/3です。

「Tokioで非同期アプリケーションを構築する」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLearn Rust Codingレッスンでコードを書いて実行できますか?

はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Async/Await入門
  2. Tokioで非同期アプリケーションを構築する
  3. Futureとタスクを扱う
← Learn Rust Codingに戻る