параллельное выполнение фьючерсов scala с использованием for-loop

#scala #for-loop #concurrent.futures

#scala #for-loop #concurrent.futures

Вопрос:

 package p1
import scala.util.Failure
import scala.util.Success
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object modCheck extends App {

  def getStudentRoolNo(name: String) = Future {
    println("getStudentRoolNo")
    name match {
      case "name1" => 1
      case "name2" => 2
      case _       => throw new Exception("No doesnt exist")
    }
  }

  def getRank(roolNo: Int) = Future {
    println("getRank")
    Thread.sleep(500)
    roolNo match {
      case 1 => "1"
      case 2 => "2"
      case _ => throw new Exception("No roolNo exist")
    }
  }

  def getDetails(roolNo: Int) = Future {
    println("getDetails")
    roolNo match {
      case 1 => "details 1"
      case 2 => "Details 2"
      case _ => throw new Exception("No details exist")
    }
  }

  def getStudentRecord(name: String) = {
    for {
      rollNo <- getStudentRoolNo(name)
      rank <- getRank(rollNo)
      details <- getDetails(rollNo)
    } yield (rank   details)

  }

  getStudentRecord("name1").onComplete {
    case Success(ground) => println(s"got my Details $ground")
    case Failure(ex)     => println("Exception!"   ex)
  }

  Thread.sleep(2000)

}
  

Я хочу выполнять функции getrank и getDetails параллельно в приведенном ниже коде (после getStudentRollNo возврата). Как я могу этого добиться?

Я попробовал приведенный ниже способ, кажется, он все еще выполняется последовательно

Пожалуйста, дайте мне знать, как выполнить параллельно

Ответ №1:

Future запускает вычисления при его создании.

for (a <- x; b <- y) yield ??? отключается x.flatMap(a => y.map(b => ???))
flatMap() и map() выполняет его аргумент после завершения Future.

getDetails() может начаться до завершения getRank() путем разделения создания Future и flatMap() вызова.

 for {
    rollNo <- getStudentRoolNo(name)
    rankFuture = getRank(rollNo)
    detailsFuture = getDetails(rollNo)
    rank <- rankFuture
    details <- detailsFuture
  } yield (rank   details)
  

Ответ №2:

Как вы, вероятно, догадались, ваш текущий код не выполняет вызовы getRank и getDetails параллельно, поскольку он находится внутри для понимания. Это синтаксический сахар для map работы. Для достижения параллелизма вам необходимо создать два фьючерса вне for-понимания.

 val student = getStudentRollNo(name)
val detailsFuture = student map {s => getRank(rollNo) }
val rankFuture = student map {s => getDetails(rollNo) }

for {
  rank <- rankFuture
  details <- detailsFuture
} yield (rank   details)
  

Комментарии:

1. Спасибо за предложение, я больше ориентируюсь на написание кода внутри цикла for (поскольку моя фактическая сложная логика очень важна, теперь принятие вышеупомянутого решения может быть немного сложным), я изменил вопрос, почему в этом случае он также выполняется последовательно?

2. Затем может быть move rankFuture = getRank(rollNo) и последующие строки для получения части. Это уменьшит беспорядок и гарантирует, что оба фьючерса выполняются параллельно

3. для { rollNo <- getStudentRoolNo(name) rankFuture = getRank(rollNo) detailsFuture = getDetails(rollNo) rank <- rankFuture details <- detailsFuture } выход (ранг детали) — это работает таким образом, спасибо 🙂

Ответ №3:

Вы можете использовать a zip в своем понимании для параллельного запуска двух фьючерсов:

   def getStudentRecord(name: String) = {
    for {
      rollNo <- getStudentRoolNo(name)
      rankRollNo <- getRank(rollNo) zip getDetails(rollNo)
    } yield rankRollNo
  }
  

В приведенном выше getRank и getDetails выполняются одновременно, и результатом является кортеж строк. Если вы хотите получить единственную строку, вам нужно будет rankRollNo разделить ее на отдельные компоненты:

 yield rankRollNo._1   rankRollNo._2