Небольшая помощь в понимании будущего и задачи Scalaz

Я пытаюсь понять идею и цель параллельного пакета scalaz, в первую очередь классов Future и Task, но при использовании их в некоторых приложениях он теперь далеко от простого последовательного аналога, тогда как scala.concurrent.Future работает более эффективно. Может ли кто-нибудь поделиться своим опытом написания параллельного/асинхронного приложения со сказазом, в основном как правильно его использовать async? Как я понимаю из источников async не использует отдельный поток, например, вызов стандартного метода future или fork/apply из scalaz работает, поэтому почему он называется async? Означает ли это, что для получения реального concurrency со сказазом мне всегда нужно называть fork(now(...)) или apply?

Ответы

Ответ 1

Я не эксперт по скалязу, но я постараюсь вам немного помочь. Позвольте мне ответить на ваши вопросы один за другим:

1) Может ли кто-нибудь поделиться своим опытом написания параллельного/асинхронного приложения со сказазом, в основном как правильно использовать его асинхронный метод?

Сначала рассмотрим подпись async:

def async[A](listen: (A => Unit) => Unit): Future[A]

Сначала это может быть немного загадочным, поэтому, как всегда, неплохо смотреть на тесты, чтобы понять возможные варианты использования. В https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/concurrent/FutureTest.scala вы можете найти следующий код:

"when constructed from Future.async" ! prop{(n: Int) =>
  def callback(call: Int => Unit): Unit = call(n)
  Future.async(callback).run must_==   
}

Как известно из подписи Future.async просто создайте новое Будущее, используя функцию подписи (A => Unit) => Unit. Это действительно означает, что Future.async принимает как функцию параметра, которая для данного обратного вызова делает все необходимые вычисления и передает результат этому обратному вызову.
Важно отметить, что Future.async не выполняет никаких вычислений сам по себе, он только готовит структуру для запуска их позже.

2) Как я понимаю из источников async не использует отдельный поток, как вызов стандартного будущего, или использует fork/apply методы из scalaz, поэтому почему он называется async, тогда?

Вы правы. Только fork и apply, кажется, работают что-либо с помощью потоков, что легко заметить, глядя на подписи, содержащие implicit pool: ExecutorService. Я не могу говорить для авторов здесь, но я думаю, что асинхронная связь связана с обратным вызовом. Это означает, что вместо того, чтобы блокировать будущее, чтобы получить результат, вы будете использовать асинхронный обратный вызов.

3) Означает ли это, что для получения реального concurrency со сказазом мне всегда нужно вызывать fork (now (...)) или применять?

Из того, что я могу сказать, да. Просто заметите, что при создании Future using синтаксис Future(x) вы используете метод apply здесь, так что это своего рода поведение по умолчанию (это нормально).

Если вы хотите лучше понять дизайн фреймов Scalaz, я могу порекомендовать вам читать "Функциональное программирование в Scala" . Я считаю, что эта книга написана главными вкладчиками Scalaz, а в главе 7 обсуждается проектирование API для чисто функциональной библиотеки parallelism. Это не совсем то же самое, что и Scalaz Future, но вы можете увидеть много общего.

Ответ 2

Вы также можете прочитать замечательное сообщение о том, что Scalaz Task и Future, которое охватывает многие не столь очевидные детали. сообщение в блоге.

Ответ 3

async используется для адаптации асинхронного API на основе обратного вызова как Future. Он назывался async, потому что он ожидал, что он будет использоваться с чем-то, что выполняется асинхронно, возможно, вызывая обратный вызов из другого потока где-то дальше по строке. Это "реальный" concurrency, если API, который вы вызываете, действительно использует его асинхронно (например, я использую Future.async с асинхронными частями AWS SDK, например AmazonSimpleDBAsyncClient).

Если вам требуется "реальный" concurrency из API-интерфейса scalaz Task, вам нужно использовать такие вещи, как fork или gatherUnordered, так как многие из API по умолчанию являются безопасными/детерминированными и перезапускаемыми, с concurrency только при явной просьбе.