Подтвердить что ты не робот

Странный случай множественных фьючерсов в Scala

Какая связь между этими классами и чертами, связанными с будущим, в Scala, и почему они посыпаются на разные пакеты?

Я нашел те:

abstract class scala.actors.Future
object         scala.actors.Futures
trait/object   scala.collection.parallel.FutureThreadPoolTasks
trait          scala.concurrent.FutureTaskRunner
trait          scala.parallel.Future    (the package consists of only this file...)

Есть ли у них существенно разные вещи или есть еще одна причина, почему они не могут быть консолидированы?

Есть ли хороший пример, показывающий, когда можно использовать одно или другое?

Изменить: Bounty для объяснения того, что делает каждый из классов/признаков/объектов и как они оправдывают их существование/как они полезны.

4b9b3361

Ответ 1

scala.actors._

abstract class Future

Прежде всего, давайте посмотрим, что говорится в документации:

Функция arity 0, сохраняющая значение типа T, которое при применении блокирует текущий актер (Actor.self) до тех пор, пока не будет доступно будущее.

И это в основном все, что есть. Если вы общаетесь с Актером из любого места вне другого актера (который может получать асинхронные ответы на сообщения просто с другим сообщением, используя ссылку sender), и вам нужен ответ на отправленное сообщение, у вас есть два варианта:

  • Отправьте сообщение блокировки, которое ждет, пока актер не закончит вычислять ваш результат.
  • Отправьте сообщение, используя метод, который возвращает "Будущее", и блокирует это Будущее только в том случае, если вам действительно нужно соответствующее значение (которое к тому времени могло быть вычислено).

Итак, будущее - это место для ценности, которая еще не существует, но, вероятно, будет в ближайшем будущем. Также интересно следующее:

Можно узнать будущее, чтобы узнать, доступно ли его значение без блокировки [с использованием "isSet" ].

Это позволяет делать все, что угодно, до тех пор, пока не будет вычислено/получено, и вы можете периодически проверять, стало ли это значение доступным.

Когда вы копаете бит в исходный код библиотеки Scala, я обнаружил, что Futures - это фактически актеры. Future сам по себе является a abstract class, который расширяется private class FutureActor. Этот последний класс является тем, который фактически реализует Future -функционал.

object Futures

object Futures, безусловно, не так интересен, поскольку это всего лишь контейнер для "Методов, работающих на фьючерсах", удобный factory метод Future, который асинхронно оценивает переданный блок, возвращая будущее, представляющее результат. Небольшим примером может быть следующее:

import scala.actors.Futures
val f = Futures.future {
    println("Start: inside block")
    val s = System.currentTimeMillis
    while(System.currentTimeMillis < (s + 1000)) {
        // Simulate computation
    }
    println("Start: end of block")
    42
}
println("After future")
println(f())
println("The end")

Что должно привести к чему-то вроде

Start: inside block
After future
Start: end of block
42
The end

Это демонстрирует, что Future -call не блокирует следующий код, пока вы на самом деле не попытаетесь получить значение будущего (обратите внимание, что вывод не детерминированный. After future также может появиться в начале вывода).

scala.collection.parallel

Этот пакет является новым для Scala 2.9.x и реализует параллельные копии для некоторых наших любимых коллекций. Все они начинаются с Par:

  • ParIterable
  • ParSeq
  • PARSET
  • ParMap

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

(1 to 10).par.map { b => print(b + " "); b * b }
3 1 6 2 7 4 5 9 10 8
    # => (1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

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

trait FutureThreadPoolTasks

Черта FutureThreadPoolTasks расширяет черту Tasks, поэтому сначала взглянем на нее. Комментарий выше черты говорит:

Характеристика, объявляющая возможности выполнения задач, используемые параллельными коллекциями.

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

Теперь признак FutureThreadPoolTasks - это просто способ вычисления задач, который использует класс java.util.concurrent.Future для его синхронизации, то есть не использует scala.actors.Future! Из источника:

Реализация объектов задач на основе API объединения потоков Java и синхронизации с использованием фьючерсов.

object FutureThreadPoolTasks

Еще раз не очень эффектный, просто сопутствующий объект, содержащий несколько (фактически только три) метода полезности, которые использует черта FutureThreadPoolTasks.

scala.concurrent

Документация по этим классам очень плохая и, по-видимому, очень мало, если таковые имеются (я не нашел ни одного) примеров, демонстрирующих использование этих классов. Я обязательно постараюсь собрать больше информации об этом и развернуть этот раздел, как только смогу!

scala.parallel

trait Future

Это похоже на "Работа в progess", поскольку пакет scala.parallel содержит только этот признак. Из того, что я могу сказать, это будет связано с реализацией Future, которая не использует Actors, но это всего лишь предположение. Подпись признака следующая

trait Future[@specialized +R] extends (() => R)

Я даже не собираюсь объяснять аннотацию @specialized или отклонения (+ перед родовым типом R), но основная идея в этом признаке заключается в том, что Будущее - это функция, которая при выполнении возвращает значение (и должна блокироваться, если она еще не была вычислена)).

Кроме того, внутри самого признака есть только два метода: apply и isDone. Я предполагаю, что isDone, как и scala.actors.Future.isSet, должен быть неблокирующим вызовом, чтобы увидеть, было ли вычисляемое значение, и метод apply должен использоваться для фактического получения значения.

Ответ 2

Ниже приводится краткое объяснение. (Детали копируются из документа scala). Сообщите мне, есть ли что-то, что вы не понимаете, и я постараюсь быть более конкретным и дать вам конкретный пример.

абстрактный класс scala.actors.Future. Вы знакомы с java.util.concorrent.Future? scala.actors.Future в основном представляет результат асинхронного вычисления, но для участников.

scala.actors.Futures. Объект (~ singleton), который содержит четыре метода утилиты для обработки scala.actors.Future.

scala.parallel.Future - (Этот был для меня новичком, но он содержит очень простые операции (apply and isDone)) его функция без параметров, которая блокирует вызывающего, если параллельное вычисление, связанное с функцией, не завершено. (function? hint: extends())

scala.collection.parallel.FutureThreadPoolTasks - из scala doc: "Реализация объектов задач на основе API объединения потоков Java и синхронизации с использованием фьючерсов". Этого достаточно?:)

scala.concurrent.FutureTaskRunner. Вы знакомы с Executor? ExecutorScheduler является одной (из трех) конкретных реализаций в стандартной библиотеке scala. executeFromActor - один из наиболее интересных методов и должен дать вам подсказку, когда вам нужно использовать этот