Как я могу запустить параллельные экземпляры функции, которая возвращает Try? - PullRequest
2 голосов
/ 21 мая 2019

У меня есть функция, которая возвращает Try, и я хочу запустить несколько ее экземпляров параллельно, но я не знаю, как это сделать - мне кажется, что я могу запустить только одинпосле другого.

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

Поведение не похоже на код блокировки- кажется, я просто не понимаю параллелизма!


Я пытался использовать Future.fromTry и выполнять их параллельно.Например:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Success, Try}

object Main extends App {
  def greet(name: String): Try[Unit] = Try {
    println(s"Hello $name!")
    Thread.sleep(1000)
    println(s"Goodbye $name!")
    ()
  }

  Seq("alice", "bob", "carol", "dave", "eve").map { name =>
    Future.fromTry { greet(name) }
  }
}

Я бы ожидал увидеть все сообщения «Hello», а затем все сообщения «Goodbye» - вместо этого кажется, что они выполняются один за другим.

Hello alice!
Goodbye alice!
Hello bob!
Goodbye bob!
Hello carol!
Goodbye carol!
Hello dave!
Goodbye dave!
Hello eve!
Goodbye eve!

Я осмотрелся и нашел предложения по настройке ExecutionContext и добавлению параллелизма - дело в том, что эта среда кажется совершенно счастливой для параллельного запуска Futures.

На той же машине с той же глобальнойExecutionContext, если я настраиваю функцию, чтобы она возвращала Future, а не Try, я вижу ожидаемый результат, и кажется, что функции работают параллельно.

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Success, Try}

object Main extends App {
  def greet(name: String): Future[Unit] = Future {
    println(s"Hello $name!")
    Thread.sleep(1000)
    println(s"Goodbye $name!")
    ()
  }

  Seq("faythe", "grace", "heidi", "ivan", "judy").map { name =>
    greet(name)
  }

  Thread.sleep(2000)  // Let the futures finish
}
Hello faythe!
Hello ivan!
Hello grace!
Hello judy!
Hello heidi!
Goodbye ivan!
Goodbye grace!
Goodbye heidi!
Goodbye judy!
Goodbye faythe!

Что яделать неправильно с Future.fromTry, что означает, что он ожидает фьючерса, чтобы закончить?Как мне сделать так, чтобы он соответствовал второму примеру?

Или я полностью лаю не то дерево?

1 Ответ

3 голосов
/ 21 мая 2019

Документация прямо заявляет, что fromTry создаст уже завершено Будущее из результата, таким образом, оно сначала оценивает функцию, а затем поднимает ее внутриБудущий контекст.Таким образом, он является полностью последовательным.

Вы можете сначала создать List[Future[String]] из имен, а затем отобразить список и сопоставить внутренние фьючерсы для выполнения вашей функции.
Или, поскольку Future ужепредставляет возможность сбоя (и внутренне использует Try), почему бы просто не использовать Future в вашей функции (как вы уже говорили ранее) .

...