2016-08-04 64 views
-2

我SEQ斯卡拉如何等待幾個期貨

我想做的迭代自動

+0

不完全是主題,但我強烈建議scalaz任務超過期貨。我發現期貨有一些奇怪的行爲,比如IO被推遲到執行結束。 – Marcin

+0

注意:OP刪除了他/她的問題。 –

回答

0
import scala.concurrent.{Await, Future} 
import scala.concurrent.duration._ 
import scala.concurrent.ExecutionContext.Implicits.global 

def f(x:String) = Future { x } 

val functions = Seq(
() => f("a"), 
() => f("b"), 
() => f(""), 
() => f("d"), 
() => f("e")) 

functions.takeWhile(x => Await.result(x(), 5 seconds) != "") 

這會給你

res0: Seq[() => scala.concurrent.Future[String]] = List(<function0>, <function0>) 

蔭不知道是否有另一種方法但爲了我的理解,如果你想根據前面的未來的結果來決定,你需要等待。

編輯: 這是一個遞歸方法。但在我看來,與迭代器的人是好的。

import scala.concurrent.{Await, Future} 
import scala.concurrent.duration._ 
import scala.concurrent.ExecutionContext.Implicits.global 

def f(x:String) = Future { x } 

val functions = Seq(
() => f("a"), 
() => f("b"), 
() => f(""), 
() => f("d"), 
() => f("e")) 


check(functions, 0) 
def check(list:Seq[() => Future[String]], pos:Int):String = { 
    if(list.size <= pos) return "" 

    val res = Await.result(list(pos)(), 5 seconds) 
    if(condition(res)) { 
    res 
    } 
    else check(list, pos+1) 
} 

def condition(c:String):Boolean = if(c == "d") true else false 

它的尾遞歸,因此你的堆棧不會溢出那麼容易。

+0

有沒有辦法等待? –

+0

如果您依賴於以前的結果,則不適用。如果你想篩選和刪除不符合條件的條目,那麼是的。 – sascha10000

+0

好的,但在這個解決方案完成時,我得到了功能,而不是價值 –

1

您可以使用iteratorflatMap。下面是一個簡化的例子:

import scala.concurrent.Await 
import scala.concurrent.Future 
import scala.concurrent.duration._ 
import scala.concurrent.ExecutionContext.Implicits.global 

val functions: Seq[() => Future[Int]] = Seq(
() => Future(1), 
() => Future(2), 
() => Future(3), 
() => Future(4), 
() => Future(5) 
) 

def checkResult(result: Int): Boolean = result > 3 

functions.iterator.flatMap { func => 
    val result = Await.result(func(), 5.seconds) 
    if (checkResult(result)) Some(result) else None 
}.next() 

該代碼將返回。

更新:

如果你只關心正確的結果並不在意所有期貨是否得到執行,你可以用fallBackTo把它們連:

import scala.util._ 

functions.tail.foldLeft[Future[Int]](functions.head().filter(checkResult)) { 
    case (result, function) => 
     result.fallbackTo(function().filter(checkResult)) 
}.onComplete { 
    case Success(result) => s"Got one: $result" 
    case Failure(exception) => s"Damn! Got NO result due to: $exception" 
} 

這將使你0123¾將與Success(4)完成與我的例子謂詞x > 3

更新2

當我發現自己有一些額外的時間,我冒昧地在其他的答案(尤其是Alexander Azarov)的一些意見和建議以貸款模式相結合方法:

import scala.annotation.tailrec 
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

val functions: Seq[() => Future[Int]] = Seq(
() => Future(1), 
() => Future(2), 
() => Future(3), 
() => Future(4), 
() => Future(5) 
) 

def checkResult(result: Int): Boolean = result > 5 

def withFirstValidResult[A, B](futureFuncs: Seq[() => Future[A]], predicate: A => Boolean, defaultValue: A)(op: (A) => B): Future[B] = { 
    @tailrec 
    @inline def find(remaining: Iterator[Future[A]]): Future[A] = { 
    if (remaining.hasNext) { 
     remaining.next().filter(predicate).recoverWith { 
     case _ => 
     find(remaining) 
     } 
    } else { 
     Future.successful { 
     println(s"No valid result found, falling back to default: $defaultValue") 
     defaultValue 
     } 
    } 
    } 


    find(futureFuncs.iterator.map(_())).map(op) 
} 

你現在可以使用這個函數來處理你想要的任何類型的期貨,並提供一個應該用第一個有效結果或者defaultValue執行的操作(雖然恕我直言,如果沒有有效的結果我寧願一個Failure適當的錯誤處理我自己):

withFirstValidResult(functions.iterator, checkResult, 0) { result => 
    println(s"Got a valid result: $result") 
}.onFailure { 
    case ex => 
    println(s"Got NO valid result: $ex") 
} 

作爲一個額外的小費,如果你想加速功能,可以迭代懶洋洋地在與futureFuncs.iterator.buffered一次評估兩種功能。這樣,當一個未來的結果正在被評估時,迭代器將自動開始下一個未來。

+0

有沒有辦法等待? –

+0

謝謝!,任何想法,爲什麼我得到Future.filter謂詞不滿意? –

+0

[NoSuchElementException:Future.filter謂詞不滿意]] –

1
def firstF[A](seq: Seq[() => Future[A]], predicate: A => Boolean): Future[A] = 
    seq.head().filter(predicate).recoverWith { 
    case _ => firstF[A](seq.tail, predicate) 
    } 

方法firstF將返回符合指定條件的第一Future。如果輸入Future均不匹配,則結果Future將爲Failure。爲了否則返回一些默認值,你根本就

firstF(seq, predicate).recover { case _ => default } 

注1這裏的代碼演示了基本原則和計劃內或計劃外的異常之間沒有區別。

注2此代碼不是尾遞歸。

+0

在這個解決方案中我得到了NoSuchElementException:空列表頭部 –

+0

@ Ben.om如果沒有元素匹配謂詞,你會得到這個異常。但是你沒有在你的問題中指定這個場景。 –

+0

好吧,它可以是任何功能沒有太多,所以在這種情況下,我需要返回瑕疵值 –