Building on the answer provided at Is there a FIFO stream in Scala?, I would like to know how to use the FIFOStream (renamed to QueueStream below) in practice, and concurrently. Since I'm rather new to Scala and Rx, I'm sticking with Futures so far, but I'd welcome alternatives (especially if using Futures in this way is too painful).
The problem is exemplified by the FIXME
comment in the below worksheet; the comment says it doesn't run, but based on past experience I think it may be deadlocking somehow.
import java.util.concurrent.{Executors, BlockingQueue, LinkedBlockingQueue}
import scala.collection.JavaConversions._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(8))
class QueueStream[A]( private val queue: BlockingQueue[Option[A]] ) {
implicit protected val defaultTimeout: Duration = 100 milliseconds
def toStream(q: BlockingQueue[Option[A]] = queue): Future[Stream[A]] = {
def computeStream(q: BlockingQueue[Option[A]] = queue): Stream[A] =
queue.take() match {
case Some(a) => Stream cons(a, computeStream())
case None => Stream.empty
}
Future {
computeStream()
}
}
def toStreamNoWait(q: BlockingQueue[Option[A]] = queue ):
Future[Stream[A]] = {
def computeStream(q: BlockingQueue[Option[A]] = queue): Stream[A] = {
val timeout = implicitly[Duration]
queue.poll(timeout.toMillis, MILLISECONDS) match {
case Some(a) => Stream cons(a, computeStream())
case None => Stream.empty
}
}
Future {
computeStream()
}
}
def size () = queue.size()
def close() = queue add None
def enqueue( as: A* ) = queue addAll as.map( Some(_) )
}
object QueueStream {
def apply[A]() = new QueueStream[A](new LinkedBlockingQueue)
}
def printIntsInQueue(queue: QueueStream[Int]): Unit = {
println("About to print some Ints...")
//FIXME: this doesn't run!:
queue.toStream().foreach { ff => ff foreach { ss =>
println(s"LENGTH IS: $ss")
}}
}
val stringList = List("abc", "123", "abc123")
val stringQueue = QueueStream[String]()
stringList.foreach{ii => stringQueue.enqueue(ii)}
val strlenQueue = QueueStream[Int]()
var sz = strlenQueue.size()
println(s"strlenQueue size is $sz")
stringQueue.toStream().foreach{ ff => ff foreach { ss =>
strlenQueue.enqueue(ss.length)
}}
sz = strlenQueue.size()
println(s"strlenQueue size is $sz")
printIntsInQueue(strlenQueue)
Edit: Working code
import java.util.concurrent.{Executors, BlockingQueue, LinkedBlockingQueue}
import scala.collection.JavaConversions._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(8))
class QueueStream[A]( private val queue: BlockingQueue[Option[A]] ) {
implicit protected val defaultTimeout: Duration = 100 milliseconds
def toStream(q: BlockingQueue[Option[A]] = queue ): Stream[A] =
queue.take() match {
case Some(a) => Stream cons(a, toStream())
case None => Stream.empty
}
def toStreamNoWait(q: BlockingQueue[Option[A]] = queue ): Stream[A] = {
val timeout = implicitly[Duration]
queue.poll(timeout.toMillis, MILLISECONDS) match {
case Some(a) => Stream cons(a, toStreamNoWait())
case null => Stream.empty
case None => Stream.empty
}
}
def size () = queue.size()
def close() = queue add None
def enqueue( as: A* ) = queue addAll as.map( Some(_) )
}
object QueueStream {
def apply[A]() = new QueueStream[A](new LinkedBlockingQueue)
}
def printIntsInQueue(queue: QueueStream[Int]): Unit = {
println("About to print some Ints...")
//FIXME: this doesn't run!:
queue.toStream().foreach {ss =>
println(s"LENGTH IS: $ss")
}
}
val stringList = List("abc", "123", "abc123")
val stringQueue = QueueStream[String]()
stringList.foreach{ii => stringQueue.enqueue(ii)}
stringQueue.close()
val strlenQueue = QueueStream[Int]()
var sz = strlenQueue.size()
println(s"strlenQueue size is $sz")
stringQueue.toStream().foreach { ss =>
strlenQueue.enqueue(ss.length)
}
strlenQueue.close()
sz = strlenQueue.size()
println(s"strlenQueue size is $sz")
printIntsInQueue(strlenQueue)