#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