使用`Future`来运行一些永不完成的循环任务是否正确?

时间:2014-11-17 00:42:29

标签: scala future

在我们的项目中,我们需要执行一个侦听队列并在循环中处理即将发生的消息的任务,该循环永远不会完成。代码看起来像:

def processQueue = {
  while(true) {
    val message = queue.next();
    processMessage(message) match {
      case Success(_) => ...
      case _ => ...
    }
  }
}

所以我们想在一个单独的线程中运行它。

我可以想象两种方法,一种是使用Thread,就像我们在Java中所做的那样:

new Thread(new Runnable() { processQueue() }).start();

另一种方法是使用Future(正如我们现在所做的那样):

Future { processQueue }

我只是想知道在这种情况下使用Future是否正确,因为据我所知(可能是错误的),Future意味着要运行一些任务,这将完成或返回一个导致未来的某些时候。但我们的任务永远不会完成。

我也想知道scala中最好的解决方案是什么。

2 个答案:

答案 0 :(得分:5)

Future应该是一个最终会存在的值,所以我认为创建一个永远不会实现的值是没有意义的。它们也是不可改变的,所以将信息传递给它们是禁忌。在Future中使用一些外部引用的队列听起来就像是黑暗的道路。

你所描述的基本上是一个Akka Actor,它有自己的FIFO队列,有一个receive方法来处理消息。它看起来像这样:

import akka.actor._

class Processor extends Actor {
    def receive = {
        case msg: String => processMessage(msg) match {
            case Success(x) => ...
            case _ => ...
        }
        case otherMsg @ Message(_, _) => {
            // process this other type of message..
        }
    }
}

您的应用可以使用Processor(或其他一些精心设计的演员组)创建此ActorSystem演员的单个实例:

val akkaSystem = ActorSystem("myActorSystem")
val processor: ActorRef = akkaSystem.actorOf(Props[Processor], "Processor")

并发送消息:

processor ! "Do some work!"

简而言之,使用像Akka这样的并发框架比在单独的线程上创建自己的处理队列更好。 Future API绝对不是最佳选择。

我建议仔细阅读Akka Documentation以获取更多信息。

答案 1 :(得分:2)

如果你只是运行一个线程(除了主线程),它就没关系了。如果你反复这样做,并且你真的想要很多单独的线程,你应该使用Thread,因为它就是这样的。期货的构建假设它们将终止,因此您可能会用完池线程。