异步前置到流

时间:2015-07-15 23:08:22

标签: scala asynchronous stream

我有一个函数,它返回一个源自套接字的无限流的执行操作。

def f1(s:Stream[T]):Stream[T] = s map {...} filter {...}

我有另一个返回有限序列的方法,我想加入这个流。

def f2():Stream[T] = ...

这就是我要找的东西:

val a = f2#:::f1(s)

问题是,f2需要一些时间来计算,f1需要尽快输出值。我想将f2包裹在Runnable中,这样我就可以在不阻塞程序其余部分的情况下计算其值。

我希望a的行为如下:如果正在计算f2,则将其添加到f1并继续输出该流的值。否则,请保持输出f1的值。我该怎么办?

1 个答案:

答案 0 :(得分:1)

您可以构建一个扩展Stream的自定义类,并为您所需的语义定义所有必要的方法。在定义自定义语义时,使用此方法将为您提供最大的灵活性。然后,您甚至可以对Stream进行丰富,使其具有withAsynPrefix方法。以下是Iterator的粗略版本,有点简单:

import scala.concurrent._
import scala.concurrent.duration._
import scala.util._
import scala.concurrent.ExecutionContext.Implicits.global

case class CombinedIterator[T](val iterator: Iterator[T], val prefix: Future[Iterator[T]]) extends Iterator[T] {
    def hasNext: Boolean = iterator.hasNext || Await.result(prefix, Duration.Inf).hasNext
    def next: T = prefix.value.collect {
        case Success(pfx) if pfx.hasNext => pfx.next
    }.getOrElse(iterator.next)
}

implicit class AsyncPrefixable[T](val iterator: Iterator[T]) extends AnyVal {
    def withAsyncPrefix(prefix: Future[Iterator[T]]): Iterator[T] = CombinedIterator(iterator, prefix)
}

那么你可以这样做:

val iterator = Iterator.from(0).take(10000)
val prefix = Future { Thread.sleep(10); Iterator(-1) }
val iteratorWithPrefix = iterator.withAsyncPrefix(prefix)
iteratorWithPrefix.toList.indexOf(-1) //Run a few times, location can vary greatly within list