Spec-Zone.ru › Scala 3.1

Пакет scala.concurrent.scala.concurrent

пакет scala.concurrent

В этом объекте пакета содержатся примитивы для конкуретного и параллельного программирования.

Руководство

Более подробное руководство по Future и Promise, включая обсуждение и примеры, можно найти по адресу https://docs.scala-lang.org/overviews/core/futures.html.

Общие импорты

При работе с Future часто бывает удобно импортировать весь пакет concurrent:

import scala.concurrent._

При использовании таких вещей, как Futures, часто требуется неявный ExecutionContext в области видимости. Общие рекомендации по этим неявным параметрам следующие.

Если код представляет собой определение класса или метода, и неявный ExecutionContext недоступен, запросите его у вызывающего метода, добавив список неявных параметров:

def myMethod(myParam: MyType)(implicit ec: ExecutionContext) = …
//Or
class MyClass(myParam: MyType)(implicit ec: ExecutionContext) { … }

Это позволяет вызывающему методу или создателю экземпляра класса решить, какой ExecutionContext следует использовать.

Для типичного использования REPL и экспериментов часто желательно импортировать глобальный ExecutionContext.

import scala.concurrent.ExcutionContext.Implicits.global

Указание продолжительности

Операции часто требуют указания продолжительности. Доступен DSL для продолжительности, чтобы облегчить определение этих значений:

import scala.concurrent.duration._
val d: Duration = 10.seconds

Использование Future для неблокирующих вычислений

Базовое использование Future простое с помощью фабричного метода на Future, который асинхронно выполняет предоставленную функцию, возвращая вам будущее результат этой функции без блокировки текущей нити. Для создания Future вам потребуется либо неявный, либо явный ExecutionContext:

import scala.concurrent._
import ExecutionContext.Implicits.global  // implicit execution context

val firstZebra: Future[Int] = Future {
 val words = Files.readAllLines("/etc/dictionaries-common/words").asScala
 words.indexOfSlice("zebra")
}

Избегайте блокировок

Хотя блокировки возможны для ожидания результатов (с обязательной продолжительностью таймаута):

import scala.concurrent.duration._
Await.result(firstZebra, 10.seconds)

и хотя это иногда необходимо, особенно в целях тестирования, блокировки в целом не рекомендуются при работе с Future и конкурентностью, чтобы избежать потенциальных тупиков и повысить производительность. Вместо этого используйте обратные вызовы или комбинаторы, чтобы оставаться в области Future:

val animalRange: Future[Int] = for {
 aardvark <- firstAardvark
 zebra <- firstZebra
} yield zebra - aardvark

animalRange.onSuccess {
 case x if x > 500000 => println("It's a long way from Aardvark to Zebra")
}

Классы-типы

Исходный код
объект Await

Await используется для обеспечения надлежащей обработки блокировок для Awaitable экземпляров.

Хотя иногда полезно, например, для тестирования, рекомендуется избегать Await всякий раз, когда это возможно — отдавая предпочтение комбинаторам и/или обратным вызовам. Методы Await's result и ready будут блокировать выполнение вызывающей нити до их возврата, что приведет к снижению производительности и, возможно, проблемам с тупиками.

Исходный код
Трейт Awaitable[+T]

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

Объект Await предоставляет методы, которые позволяют получить результат Awaitable, блокируя текущую нить до завершения Awaitable или наступления таймаута.

Исходный код
Трейт Batchable

Маркерный трейт для обозначения Runnable, который может быть разделен по группам BatchingExecutors

Исходный код
Трейт BlockContext

Контекст, который получает уведомления от scala.concurrent.blocking, когда нить собирается заблокироваться. По сути, этот трейт предоставляет реализацию для scala.concurrent.Await. scala.concurrent.Await.result и scala.concurrent.Await.ready находит экземпляр BlockContext, сначала проверив, предоставлен ли он через BlockContext.withBlockContext, а в противном случае, проверив, является ли Thread.currentThread экземпляром BlockContext. Таким образом, пул потоков может иметь свои экземпляры java.lang.Thread которые реализуют BlockContext. Используется по умолчанию BlockContext если нить не реализует BlockContext.

Как правило, вы хотите связать с предыдущим BlockContext, как в этом примере:

val oldContext = BlockContext.current
val myContext = new BlockContext {
  override def blockOn[T](thunk: => T)(implicit permission: CanAwait): T = {
    // you'd have code here doing whatever you need to do
    // when the thread is about to block.
    // Then you'd chain to the previous context:
    oldContext.blockOn(thunk)
  }
}
BlockContext.withBlockContext(myContext) {
  // then this block runs with myContext as the handler
  // for scala.concurrent.blocking
}
Компаньон объект

Исходный код
объект BlockContext

Компаньон класс

Исходный код@implicitNotFound("Не вызывайте методы `Awaitable` напрямую, используйте объект `Await`.")
закрытый трейт CanAwait

Этот маркерный трейт используется объектом Await для обеспечения того, что Awaitable.ready и Awaitable.result не вызываются напрямую кодом пользователя. Неявный экземпляр этого трейта доступен только тогда, когда код пользователя в настоящее время вызывает методы в объекте Await.

Исходный код@implicitNotFound("Не найден неявный ExecutionContext. Вы можете добавить\nпараметр (implicit ec: ExecutionContext) в свой метод.\n\nExecutionContext используется для настройки того, как и в каких\nпулах потоков будут выполняться асинхронные задачи (такие как Future),\nпоэтому конкретный ExecutionContext важен.\n\nЕсли ваше приложение не определяет ExecutionContext где-либо ещё,\nрассмотрите возможность использования глобального ExecutionContext Scala, определив\nследующее:\n\nimplicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global")
Трейт ExecutionContext

%%CODE_BLOCK_28%%% может выполнять логику программы асинхронно, как правило, но необязательно, в пуле потоков.

%%CODE_BLOCK_29%%% общего назначения должен быть асинхронным при выполнении любого Runnable, который передается в его метод execute. %%CODE_BLOCK_32%%% специального назначения может быть синхронным, но должен передаваться только в код, который явно безопасен для запуска с помощью синхронно работающего ExecutionContext.

API, такие как Future.onComplete, требуют, чтобы вы предоставили обратный вызов и неявный ExecutionContext. Неявный ExecutionContext будет использоваться для выполнения обратного вызова.

Хотя можно просто импортировать scala.concurrent.ExecutionContext.Implicits.global для получения неявного ExecutionContext, разработчики приложений должны тщательно продумать, где они хотят определить политику выполнения; в идеале, в одном месте на приложение — или в логически связанной части кода — будет принято решение о том, какой ExecutionContext использовать. То есть, вы, в основном, хотите избежать жесткого кодирования, особенно с помощью импорта, scala.concurrent.ExecutionContext.Implicits.global. Рекомендуемый подход — добавить (implicit ec: ExecutionContext) к методам или параметрам конструктора класса, которым необходим ExecutionContext.

Затем локально импортируйте определённый ExecutionContext в одном месте для всего приложения или модуля, передавая его неявным образом отдельным методам. В качестве альтернативы, определите локальную неявную переменную val с требуемым ExecutionContext.

Настройка ExecutionContext может быть уместна для выполнения кода, который блокирует операции ввода-вывода или выполняет длительные вычисления. ExecutionContext.fromExecutorService и ExecutionContext.fromExecutor — хорошие способы создания настраиваемого ExecutionContext.

Цель ExecutionContext — лексически ограничить выполнение кода. То есть каждый метод, класс, файл, пакет или приложение определяет, как выполнять свой собственный код. Это позволяет избежать проблем, таких как выполнение обратных вызовов приложения в пуле потоков, принадлежащем библиотеке сетевых операций. Размер пула потоков сетевой библиотеки можно безопасно настроить, зная, что будут затронуты только сетевые операции этой библиотеки. Выполнение обратных вызовов приложения можно настроить отдельно.

Компаньон объект

Исходный код
объект ExecutionContext

Содержит методы-фабрики для создания контекстов выполнения.

Компаньон класс

Исходный код
Трейт ExecutionContextExecutor extends ExecutionContext with Executor

%%CODE_BLOCK_28%%% который также является Java Executor.

Исходный код
Трейт ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService

%%CODE_BLOCK_28%%% который также является Java ExecutorService.

Исходный код
Трейт Future[+T] extends Awaitable[T]

%%CODE_BLOCK_50%%% представляет собой значение, которое может или может не быть *в настоящее время* доступно, но будет доступно в какой-то момент, или исключение, если это значение не может быть предоставлено.

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

END_OF_DOCUMENT_MARKER
import ExecutionContext.Implicits.global
val s = "Hello"
val f: Future[String] = Future {
  s + " future!"
}
f foreach {
  msg => println(msg)
}
См. также

Futures и Promises

Компаньон объект

Исходный код
объект Future

Объект-компаньон Future.

Компаньон класс

Исходный код
трайт Promise[T]

Promise — это объект, который может быть завершён значением или ошибкой.

Promise всегда должен быть завершён, будь то успехом или ошибкой, чтобы избежать нежелательного удержания ресурсов для обратных вызовов или преобразований связанных с ним Futures.

Компаньон объект

Исходный код
объект Promise

Компаньон класс

Типы

Исходный код
тип CancellationException = CancellationException

Исходный код
тип ExecutionException = ExecutionException

Исходный код
тип TimeoutException = TimeoutException

Конкретные методы

Исходный код@throws(scala.Predef.classOf[scala.Exception])
final def blocking[T](body: => T): T

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

Блокирование на Awaitable следует выполнять с помощью Await.result, а не blocking.

Параметры значения
body

Фрагмент кода, содержащий потенциально блокирующие или длительные вызовы.

Исключения
CancellationException

если вычисление было отменено

InterruptedException

в случае прерывания ожидания в блокирующем body

© 2002-2022 EPFL, with contributions from Lightbend.
Licensed under the Apache License, Version 2.0.
https://scala-lang.org/api/3.1.1/scala/concurrent.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API