Scala并行集合-如何提前返回?

Scala并行集合-如何提前返回?,scala,parallel-processing,scala-2.9,Scala,Parallel Processing,Scala 2.9,我有一个可能的输入值列表 val inputValues = List(1,2,3,4,5) 我有一个很长的计算函数,它给了我一个结果 def reallyLongFunction( input: Int ) : Option[String] = { ..... } 使用scala并行集合,我可以轻松地 inputValues.par.map( reallyLongFunction( _ ) ) 为了得到所有的结果,并行地。问题是,我并不想要所有的结果,我只想要第一个结果。一旦我的一个输入

我有一个可能的输入值列表

val inputValues = List(1,2,3,4,5)
我有一个很长的计算函数,它给了我一个结果

def reallyLongFunction( input: Int ) : Option[String] = { ..... }
使用scala并行集合,我可以轻松地

inputValues.par.map( reallyLongFunction( _ ) )
为了得到所有的结果,并行地。问题是,我并不想要所有的结果,我只想要第一个结果。一旦我的一个输入成功了,我就想要我的输出,并且想要继续我的生活。这做了很多额外的工作

那么,我怎样才能两全其美呢?我想

  • 获取从长函数返回的第一个结果
  • 停止所有其他线程的无用工作
  • 编辑- 我像一个愚蠢的java程序员一样通过

    @volatile var done = false;
    
    在my
    reallyLongFunction
    中设置并检查。这是可行的,但感觉不太舒服。想要一个更好的方法来实现这一点……

    (更新:不,它不起作用,不做地图)

    这样做是否可行:

    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非常相似,只是你不必看它;-)

    我用与huynhjl相同的方式解释您的问题,但如果您只想搜索并放弃
    None
    s,您可以这样做,以避免在找到合适的结果时重复计算:

    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
    似乎做了很多不必要的工作(请参阅),因此这可能无法很好地工作,至少在当前版本的Scala中是如此


    Volatile标志用于并行集合(查看
    find
    exists
    、以及
    forall
    )的源代码,因此我认为您的想法很好。如果可以在函数本身中包含该标志,实际上会更好。它破坏了函数的引用透明性(即,对于某些输入,函数现在有时返回
    None
    ,而不是
    Some
    ),但由于您正在放弃停止的计算,这应该无关紧要。

    如果您愿意使用非核心库,我认为Futures将非常适合此任务。例如:

    • 阿克卡的未来包括
    • 推特的未来包括

    ……这两个函数都能实现你正在寻找的功能。

    侧注(不是你的问题的答案):这是更简单的:<代码>输入值。PAR。MAP(RealLealActuple)类似:它看起来不像我的并行集合,或者叉连接框架被设计来处理这种情况。如果计算很长,因为它是CPU密集型的,那么想要计算所有结果或在内核之间分配负载,而不是让所有内核都工作来计算结果,这似乎是浪费。如果计算很长,因为它正在等待一些IO,那么未来或参与者似乎更合适。对于每个输入,它是一个纯粹的单线程计算,每个输入大约需要30秒的CPU时间。关于使用fork-join拆分工作的完美案例,如果有更干净的方法在第一次成功回答时中止。@b好吧,我可能误解了您的用例。它认为这与此相同:给定n个核,接受n个输入,启动n个计算,然后等待第一个完成。因此,有关拆分任务和从其他队列窃取工作的整个业务都没有发挥作用……我如何才能获得reallylongFunction的结果?我不太明白这个语法,哼,我搞砸了;find当然返回原始值,而不是计算值。不管这个答案@HavocP-我也遇到过好几次这个问题:(为什么Scala没有在它的集合中定义类似findMap[B](fn:A=>(B,布尔))的东西?据我所知,
    view
    是“findMap”的原因函数是不需要的。但我只是尝试将它与
    par
    混合使用,它似乎失去了惰性,因此可能在这里不起作用。我不希望先完成,我希望先完成,结果是“find”存在于即将发布的Akka 2.0中,但在此之前,它相当容易实现:我非常喜欢将惰性结果存储在find中,然后用映射将其取出。我不能完全编译此函数,因为我的“f”函数除了I参数外还需要另外两个参数(与我正在拆分的内容无关,并且在所有调用中都是常量)…因此需要从语法POV中找出这一点。也许我应该将其转换为…@bwawok
    新计算((arg1,arg2,arg3),(f_2;).tupled)
    将在不修改
    计算
    类的情况下工作,假设
    f
    接受3个参数。或者,您可以使计算类具有不同的arity。