我是Scala的初学者Futures
/ Promises
。
我正在尝试使用Futures
(使用回调)执行此操作:
以下是代码:
// Final write container to hold the result.
val promise = Promise[List[GitData]]()
val repositoriesF = Future {
GitDriver.repositoriesOf(request.user)
}
val gitRepositories = Promise[List[GitRepository]]()
repositoriesF onSuccess {
case repositories => {
val contributors = Promise[List[Contributor]]()
val contributorsF = Future(repositories.map(GitDriver.contributors))
val readMe = Promise[List[String]]
val readMeF = Future(repositories.map(GitDriver.readme))
contributorsF.onSuccess {
case contrib => contributors.success(contrib.flatten)
}
readMeF.onSuccess {
case r => readMe.success(r)
}
val extractedContributors = contributors.future.value
val extractedReadme = readMe.future.value
println(extractedContributors.size)
println(extractedReadme.size)
}
}
Await.ready(repositoriesF, Duration.Inf)
贡献者和自述文件的大小始终为零。
我解决这个问题的方法是,我可以通过Futures
将贡献者和自述文件的提取平行化,因为它们不相互依赖。他们只需要一个存储库对象。
我在这里缺少什么?我确信有更多优雅的解决方案用于理解,地图,dsls等。但只是好奇地走到这一个的底部!感谢。
答案 0 :(得分:2)
你正在做一些奇怪的事情。根据您的问题,主要问题是您要在此块中打印值:
repositoriesF onSuccess {
case repositories => {
...
所以从某种意义上说,你只是在等待FIRST异步计算,并且只为你需要的其他信息设置回调(自述文件和贡献者)。在设置回调之后,那些没有完成,你没有结果。
第二个奇怪的事情是你在第一个未来做Await()
而不做其他计算。您很可能希望等待所有信息都可用。
你正在做的第三个奇怪的事情是使用太多的承诺。你不想在获得某些结果时使用Promise,但是当你必须将Future返回给其他人并且需要一种方法来完成未来,当你不再能够访问未来时。
至于如何解决你的问题,我会用理解链接期货:
val futureGitData = for {
repos <- Future { GitDriver.repositoriesOf(request.user) }
repo <- repos
readme <- Future { GitDriver.readme(repo) }
contributors <- Future { GitDriver.contributors(repo) }
} yield (repo, readme, contributors)
请注意,这有更好的并行性,因为我为每个存储库创建了不同的未来。你在做什么,Future(repositories.map(GitDriver.readme))
会同步地做地图并返回一个未来。
请注意,我在此设备中没有Scala,因此代码可能不完美,但应该给你一个想法。
答案 1 :(得分:0)
目前您打印贡献者和自述文件的大小时,未来可能尚未完成,因此contributors.future.value
将返回无。
您可以尝试这样的事情:
val repositoriesF = Future {
GitDriver.repositoriesOf(request.user)
}
val contributorsAndReadmeFuture = for {
repositories <- repositoriesF
contributors <- Future(repositories.map(GitDriver.contributors))
readme <- Future(repositories.map(GitDriver.readme))
} yield (contributors, readme)
contributorsAndReadmeFuture onSuccess {
case (constributors, readme) =>
println(constributors.size)
println(readme.size)
}
答案 2 :(得分:0)
您的future.value
和println
行在Futures
之前执行(Future(...)
的明确行和Promise.future
中设置的onSuccess
是完成。
Future
的值仍为None
,与之相比:
val p = Promise[Int]()
p.future.value
// Option[scala.util.Try[Int]] = None
p.future.value.size
// Int = 0
由于您希望继续使用您的解决方案,您可以执行类似的操作(没有多余的Promises
):
repositoriesF onSuccess {
case repositories =>
val contributorsF = Future(repositories.flatMap(GitDriver.contributors))
val readMeF = Future(repositories.map(GitDriver.readme))
contributorsF zip readMeF onSuccess {
case (contrib, readme) =>
println(contrib.size)
println(readme.size)
}
}