我有一个可能的输入值列表
val inputValues = List(1,2,3,4,5)
我有一个很长的计算功能,给我一个结果
def reallyLongFunction( input: Int ) : Option[String] = { ..... }
使用scala并行集合,我可以轻松完成
inputValues.par.map( reallyLongFunction( _ ) )
同时得到所有结果。问题是,我真的不想要所有的结果,我只想要FIRST的结果。一旦我的一个输入成功,我想要我的输出,并希望继续我的生活。这做了很多额外的工作。
那么我如何才能充分利用这两个世界呢?我想
修改 我通过
解决了它像一个愚蠢的java程序员@volatile var done = false;
在reallyLongFunction
内设置并检查了哪个。这有效,但感觉不太scala。想要一个更好的方法来做到这一点......
答案 0 :(得分:4)
(更新:不,它不起作用,不做地图)
是否可以执行以下操作:
inputValues.par.find({ v => reallyLongFunction(v); true })
实现使用:
protected[this] class Find[U >: T](pred: T => Boolean, protected[this] val pit: IterableSplitter[T]) extends Accessor[Option[U], Find[U]] {
@volatile var result: Option[U] = None
def leaf(prev: Option[Option[U]]) = { if (!pit.isAborted) result = pit.find(pred); if (result != None) pit.abort }
protected[this] def newSubtask(p: IterableSplitter[T]) = new Find(pred, p)
override def merge(that: Find[U]) = if (this.result == None) result = that.result
}
看起来与你的@volatile非常相似,除非你不必看它; - )
答案 1 :(得分:3)
我以与huynhjl相同的方式解释了你的问题,但如果你只是想搜索并丢弃None
,你可以做这样的事情,以避免在合适的结果是重复计算时实测值:
class Computation[A,B](value: A, function: A => B) {
lazy val result = function(value)
}
def f(x: Int) = { // your function here
Thread.sleep(100 - x)
if (x > 5) Some(x * 10)
else None
}
val list = List.range(1, 20) map (i => new Computation(i, f))
val found = list.par find (_.result.isDefined)
//found is Option[Computation[Int,Option[Int]]]
val result = found map (_.result.get)
//result is Option[Int]
但并行集合的find
似乎做了很多不必要的工作(参见this question),所以这可能效果不好,至少使用当前版本的Scala。
并行集合中使用了易失性标记(请查看find
,exists
和forall
的来源),因此我认为您的想法很好。如果你可以在函数本身中包含标志,那实际上会更好。它会杀死你的函数的引用透明度(即对于某些输入,你的函数现在有时会返回None
而不是Some
),但是由于你丢弃了已停止的计算,这应该不重要。
答案 2 :(得分:2)
如果你愿意使用非核心库,我认为期货将是这项任务的一个很好的匹配。例如:
...两者似乎都能启用您正在寻找的功能。