Разница между {zip map} и {flatMap map} в Future of Scala - PullRequest
0 голосов
/ 09 июля 2020

Я читаю 《руки на scala》, и одно из его упражнений - распараллеливание сортировки слиянием.

Я хочу знать, почему for-complation, который можно перевести в flatMap и map, занимает больше времени чем почтовый индекс и карта.

мой код:

def mergeSortParallel0[T: Ordering](items: IndexedSeq[T]): Future[IndexedSeq[T]] = {
    if (items.length <= 16) Future.successful(mergeSortSequential(items))
    else {
        val (left, right) = items.splitAt(items.length / 2)
        for (
          l <- mergeSortParallel0(left);
          r <- mergeSortParallel0(right)
        ) yield merge(l, r)
    }
}
  

стандартный ответ, предоставленный книгой:

def mergeSortParallel0[T: Ordering](items: IndexedSeq[T]): Future[IndexedSeq[T]] = {
    if (items.length <= 16) Future.successful(mergeSortSequential(items))
    else {
        val (left, right) = items.splitAt(items.length / 2)
        mergeSortParallel0(left).zip(mergeSortParallel0(right)).map{
            case (sortedLeft, sortedRight) => merge(sortedLeft, sortedRight)
        }
    }
}

1 Ответ

2 голосов
/ 09 июля 2020

flatMap или map - это последовательные операции над Scala Future и сами по себе не имеют ничего общего с параллельным запуском вещей. Их можно рассматривать как простые обратные вызовы, выполняемые после завершения Future. Другими словами, предоставленный код внутри map(...) или flatMap(...) начнет выполняться только после завершения предыдущего Future.

zip, с другой стороны, будет запускать ваши Futures параллельно и возвращать результат как кортеж, когда оба они завершены. Точно так же вы можете использовать zipWith, который принимает функцию для преобразования результатов двух Futures (объединяет операции zip и map):

      mergeSortParallel0(left).zipWith(mergeSortParallel0(right)){
        case (sortedLeft, sortedRight) => merge(sortedLeft, sortedRight)
      }

Другой способ добиться параллелизма - объявить Futures за пределами for-понимания. Это работает, поскольку фьючерсы в Scala являются «нетерпеливыми», и они запускаются, как только вы их объявляете (присваиваете val):

  def mergeSortParallel0[T: Ordering](items: IndexedSeq[T]): Future[IndexedSeq[T]] = {
    if (items.length <= 16) Future.successful(mergeSortSequential(items))
    else {
      val (left, right) = items.splitAt(items.length / 2)
      val leftF = mergeSortParallel0(left)
      val rightF = mergeSortParallel0(right)

      for {
        sortedLeft <- leftF
        sortedRight <- rightF
      } yield {
        merge(sortedLeft, sortedRight)
      }
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...