0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

FutureとPromiseの基礎

非同期の結果を表す `Future` と、その完了に使う `Promise` の基本概念を理解します。

「FutureとPromiseの基礎」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン1/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全3レッスンが含まれています。

非同期コード:重要な理由

プログラミングでは、タスクは同期的(順番に実行)にも非同期的(前のタスクの完了を待たずに開始可能)にも実行できます。

非同期プログラミングは、ネットワークリクエストやデータベースクエリのような時間のかかる処理を待っている間も停止しない、応答性の高いアプリケーションを構築するために重要です。

ブロッキング呼び出しの問題

プログラムがインターネットからデータを取得する必要があるとします。この操作がブロッキングである場合、データが届くまでプログラムは一時停止し、ほかの処理を何も行いません。

これにより、ユーザーインターフェースが「フリーズ」したり、サーバー側アプリケーションの効率が低下したりします。メインの処理の流れを止めずに、これらのタスクをバックグラウンドで実行する方法が必要です。

Scala Futuresの紹介

ScalaのFutureは、非同期プログラミングのための強力なツールです。将来のある時点で利用可能になる値を表しますが、現時点ではまだ利用できない場合があります。

  • コーヒーを注文する場合に似ています。レシート(Future)を受け取り、コーヒーができるまでの間にほかのことができます。
  • コーヒーができると、レシートに飲み物(結果)が「完了」として記録されます。

最初のFutureを作成する

計算をFuture { ... }でラップすると、Futureを作成できます。この計算は別のスレッドで実行されます。

これらのタスクをスケジュールするにはExecutionContextが必要です。ここでは簡単にするため、グローバルのものを使用します。

import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object Main extends App {
  println("Starting computation...")

  val f: Future[Int] = Future {
    Thread.sleep(1000) // Simulate a long operation
    42
  }

  f.onComplete {
    case Success(value) => println(s"Result: $value")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  println("Computation started, continuing...")
  // Keep main thread alive for a bit to see Future's result
  Thread.sleep(2000)
}

ExecutionContextを理解する

ExecutionContextは、非同期計算を実行するスレッドプールです。

  • タスクをいつ、どのように実行するかを管理します。
  • 簡単な例では、デフォルトのスレッドプールを提供するscala.concurrent.ExecutionContext.Implicits.globalがよく使われます。
  • 実際のアプリケーションでは、リソース使用量をより適切に制御するため、専用のスレッドプールを設定することがあります。

Futureの結果を処理する:onComplete

onCompleteメソッドは、Futureが成功したか失敗したかにかかわらず、処理が完了したときに何を行うかを定義するために使います。

Success(value)またはFailure(exception)のいずれかになるscala.util.Tryを処理する関数を受け取ります。

import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object Main extends App {
  val futureSuccess = Future { 10 / 2 }
  val futureFailure = Future { 10 / 0 }

  futureSuccess.onComplete {
    case Success(result) => println(s"Success: $result")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  futureFailure.onComplete {
    case Success(result) => println(s"Success: $result")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  Thread.sleep(100) // Allow Futures to complete and print
}

簡単なハンドラー:SuccessとFailure

単純なケースでは、成功した結果だけ、またはエラーだけを処理するために、それぞれonSuccessとonFailureを使えます。

  • onSuccessは、成功時の値を処理する関数を受け取ります。
  • onFailureは、例外を処理する関数を受け取ります。
  • これらはonCompleteを基盤として構築された便利なメソッドです。
import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App {
  val futureValue = Future { "Hello, Scala!" }

  futureValue.onSuccess { case msg => println(s"Got message: $msg") }
  futureValue.onFailure { case e => println(s"Oops, an error: ${e.getMessage}") }

  val futureError = Future { throw new RuntimeException("Something broke!") }

  futureError.onSuccess { case msg => println(s"Got message: $msg") }
  futureError.onFailure { case e => println(s"Oops, an error: ${e.getMessage}") }

  Thread.sleep(100) // Allow Futures to complete and print
}

Scala Promiseとは

Futureが結果の読み取り専用プレースホルダーであるのに対し、Promiseは値または例外で一度だけ完了できる書き込み専用コンテナです。

  • PromiseはFutureを完了させるために使います。
  • Promiseを作成し、それに関連付けられたFutureを取得して、結果の準備ができた時点でPromiseを完了させます。

Promiseを完了させる

success()またはfailure()メソッドを使ってPromiseを完了させることができます。Promiseが完了すると、関連付けられたFutureも完了します。

Promiseを2回以上完了させようとすると、エラーになります。

import scala.concurrent.{Future, Promise, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object Main extends App {
  val p = Promise[String]() // Create a Promise that will hold a String
  val f: Future[String] = p.future // Get the Future associated with the Promise

  f.onComplete {
    case Success(value) => println(s"Future completed with: '$value'")
    case Failure(e) => println(s"Future failed with: ${e.getMessage}")
  }

  // Simulate an async operation completing the promise
  Future {
    Thread.sleep(500)
    p.success("Data fetched successfully!") // Complete the Promise
  }

  println("Promise created, waiting for completion...")
  Thread.sleep(1000) // Keep main thread alive to see Future's result
}

FutureとPromiseを組み合わせる

FutureとPromiseは、しばしば連携して使われます。よくあるパターンは、外部システムや古いコールバックベースのAPIからFutureの完了を手動で制御する必要がある場合に、Promiseを使うことです。

これにより、Futureベースではない非同期処理をFutureモデルにラップし、Futureベースのコードと互換性を持たせることができます。

import scala.concurrent.{Future, Promise, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object Main extends App {
  def performLongTask(data: String): Future[String] = {
    val p = Promise[String]()
    // Simulate an external system or callback-based API
    Future {
      Thread.sleep(700)
      if (data == "fail") p.failure(new Exception("Task failed!"))
      else p.success(s"Processed: $data")
    }
    p.future // Return the Future that will be completed by the Promise
  }

  val task1 = performLongTask("input data")
  task1.onComplete { case Success(res) => println(s"Task 1: $res") case Failure(e) => println(s"Task 1: ${e.getMessage}") }

  val task2 = performLongTask("fail")
  task2.onComplete { case Success(res) => println(s"Task 2: $res") case Failure(e) => println(s"Task 2: ${e.getMessage}") }

  Thread.sleep(1500) // Keep main thread alive for results
}

クイックチェック:FutureとPromise

ScalaにおけるFutureとPromiseの役割を正しく説明している文は、次のうちどれでしょうか。

まとめ:FutureとPromise

よくできました!このレッスンでは、Scalaにおける非同期プログラミングの基礎を学びました。

  • Future:将来的に利用可能になる結果を表すプレースホルダーです。
  • Promise:Futureを手動で完了させるために使用する、一度だけ書き込み可能なコンテナーです。
  • ExecutionContext:非同期タスクの実行をスケジュールします。
  • onComplete、onSuccess、onFailureを使用してFutureの結果を処理する方法です。

これらの概念は、より複雑な非同期パターンを構築するための基本要素です。

よくある質問

「FutureとPromiseの基礎」レッスンは無料ですか?

はい。「FutureとPromiseの基礎」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全3レッスンが含まれています。

「FutureとPromiseの基礎」で何を学びますか?

非同期の結果を表す `Future` と、その完了に使う `Promise` の基本概念を理解します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

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

「FutureとPromiseの基礎」レッスンにはどのくらい時間がかかりますか?

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

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

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

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

  1. FutureとPromiseの基礎
  2. 非同期処理の組み立て
  3. Futureでのエラー処理
← Scala for Backend Engineering & Functional Programmingに戻る