Имам списък с идентификационни номера в Scala и за всеки идентификатор, който пускам бъдеще, за да извърша операция по базата данни по-долу:
import myPackage.myExecutionContext
def doDbOperation(ids: List[Long]) = ids.map { id =>
Future(get(id))
}
Забелязвам, че Фючърсите се изпълняват едва след товаПреминаването на списъка е завършено (списъкът е доста голям). Как да направя бъдещето да бъде стартирано, когато е възможно (въз основа на наличните нишки), без да се чака завършването на траверса?
Отговори:
4 за отговор № 1Погледни Future.traverse
, Документите казват: "Това е полезно за извършване на паралелна карта. Например, за да приложите функция към всички елементи от списъка паралелно".
Future.traverse(ids)(id => Future(get(id)))
1 за отговор № 2
Не мога да обясня наблюдаваното поведение (Бъдещото тяло не се изпълнява до завършването на картата). Следното ще отпечата Running future while mapping
:
package org.example
import scala.concurrent.{ Future }
import scala.concurrent.ExecutionContext.Implicits.global
object Test extends App {
@volatile var hasStarted = false
val ids: List[Long] = Range.Long(0L, 100000L, 1L).toList
val res = ids.map({ id =>
val res = Future {
if (!hasStarted) hasStarted = true
id
}
if (hasStarted) println("Running future while mapping")
res
})
}
Което има смисъл; Future.apply
не се изпълнява различно в зависимост от това дали се нарича вътре в a map
или a Future.traverse
.
Re: Future.traverse
Типовете връщане са различни.
ids.map { id => Future(get(id)) }
се завръща List[Future[DBObject]]
но
Future.traverse(ids)(id => Future(get(id)))
се завръща Future[List[DBObject]]
Future[List[DBObject]]
е почти винаги по-полезен, но променяте семантиката (и може би не искате).