我在Scala中有一个id列表,对于每个id,我启动了一个未来来执行数据库操作,如下所示:
import myPackage.myExecutionContext
def doDbOperation(ids: List[Long]) = ids.map { id =>
Future(get(id))
}
我注意到Futures只在列表遍历完成后执行(List非常大)。如何在不等待遍历完成的情况下尽可能地启动Future(基于可用线程)?
答案 0 :(得分:4)
看看Future.traverse
。文档说“这对于执行并行映射很有用。例如,将函数并行应用于列表的所有项”。
Future.traverse(ids)(id => Future(get(id)))
答案 1 :(得分:1)
我无法解释观察到的行为(在地图遍历完成之前,未来的主体不会执行)。以下内容将打印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
的效果不同,具体取决于是在map
还是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]]
几乎总是更有用,但你正在改变语义(也许你不想这样做)。