0Pricing
Scala for Backend Engineering & Functional Programming · Урок

Введение в Future и Promise

Изучите основные концепции `Future` для асинхронных результатов и `Promise` для их завершения.

«Введение в Future и Promise» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 1 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.

Асинхронный код: почему это важно

В программировании задачи могут выполняться синхронно (одна за другой) или асинхронно (задачи могут запускаться, не дожидаясь завершения предыдущих).

Асинхронное программирование необходимо для создания отзывчивых приложений, которые не зависают во время ожидания медленных операций, таких как сетевые запросы или запросы к базе данных.

Проблема блокирующих вызовов

Представьте, что вашей программе нужно получить данные из интернета. Если эта операция блокирующая, программа приостановится и не будет делать ничего другого, пока данные не поступят.

Это может привести к «зависанию» пользовательского интерфейса или к неэффективной работе приложений на стороне сервера. Нам нужен способ выполнять такие задачи в фоновом режиме, не останавливая основной поток выполнения.

Знакомство с Future в Scala

Future в Scala — мощный инструмент асинхронного программирования. Он представляет значение, которое может быть недоступно сейчас, но появится в некоторый момент в будущем.

  • Представьте, что вы заказали кофе: вы получаете чек (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 — успешно или с ошибкой.

Он принимает функцию, работающую с scala.util.Try, который может быть либо Success(value), либо Failure(exception).

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
}

Что такое Promise в Scala?

Если Future — это доступная только для чтения заготовка результата, то Promise — это контейнер, который можно заполнить один раз значением или исключением.

  • Promise используется для завершения Future.
  • Вы создаёте Promise, получаете связанный с ним Future, а затем завершаете Promise, когда результат готов.

Выполнение Promise

Завершить Promise можно с помощью его методов success() или failure(). После завершения Promise связанный с ним Future также будет завершён.

Попытка завершить Promise более одного раза приведёт к ошибке.

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 часто работают вместе. Распространённый подход — использовать Promise, когда нужно вручную управлять завершением Future, например из внешней системы или старого API на основе обратных вызовов.

Это позволяет обернуть асинхронные операции, не основанные на 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

Какие из следующих утверждений правильно описывают роли Future и Promise в Scala?

Итоги: Future и Promise

Отличная работа! В этом уроке Вы изучили основы асинхронного программирования в Scala:

  • Future: заполнитель для результата, который станет доступен позднее.
  • Promise: контейнер с однократной записью, используемый для ручного завершения объекта Future.
  • ExecutionContext: планирует выполнение асинхронных задач.
  • Как обрабатывать результаты Future с помощью onComplete, onSuccess и onFailure.

Эти понятия служат строительными блоками для более сложных асинхронных шаблонов!

Часто задаваемые вопросы

Урок «Введение в Future и Promise» бесплатный?

Да — полный текст урока «Введение в Future и Promise» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс 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/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?

Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 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