Странный случай множественных фьючерсов в Scala - PullRequest
16 голосов
/ 03 июня 2011

Какова связь между этими классами Future и чертами в 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...)

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

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

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

Ответы [ 2 ]

11 голосов
/ 15 июня 2011

scala.actors._

abstract class Future

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

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

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

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

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

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

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

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

object Futures

object Futures далеко не так интересен, так как это всего лишь контейнер для "Методы, которые работают с фьючерсами" , удобный фабричный метод 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

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

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

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

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

4 голосов
/ 12 июня 2011

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

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

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

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

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

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

...