Scala Future vs Thread用于长期运行的任务,但没有结果

时间:2016-07-27 15:40:38

标签: multithreading scala asynchronous concurrency future

我想在Scala 2.11中构建一个侦听套接字的简单服务器。它应该异步读取套接字中的数据,并将数据从RxScala传递给Observable。

我有一个Java ServerSocket,应该使用阻塞的方法readData从中读取数据。此方法以启动启动并运行直到整个程序停止:

val server = new ServerSocket(port)
def readData(server: ServerSocket): Unit = ???

当从套接字读取数据时,我发现了两种不同的方法来避免阻塞整个程序:

new Thread {
  override def run(): Unit = {
    readData(server)
  }
}.start()

Future {
  blocking {
    readData(server)
  }
}

因为Future中没有包含返回值,然后可以将其传递给其他任务,Future的唯一任务就是使计算无阻塞。所以我想知道这些方法之间是否存在更大的差异?看看Future的实现,看起来它也创建并运行带有给定块的Runnable。那么,如果一个人有一个没有结果的单一且永久/长期运行的任务,那么这些方法中的一个更好吗?

2 个答案:

答案 0 :(得分:3)

  

如果一个人有很长或永远,那么这些方法中的一个更可取   运行没有结果的任务?

这两个示例的不同之处在于,前者为每个请求分配一个新线程,第二个示例隐式使用Scala的默认ExecutionContext,后者由ForkJoinPool支持,这是基本上是一个可以根据需要扩展/缩小的线程池。

需要记住一个线程不是免费的,它需要分配一个堆栈(根据操作系统而变化),需要进行系统调用来注册该线程等等(你可以在Why is creating a Thread said to be expensive?)中阅读更多内容。

一般来说,我选择后者"天真"使用Futureblocking一起使用全局ExecutionContext的方法。最重要的是,我会对我的代码进行基准测试,以确保我对代码的行为方式感到满意,然后根据这些调查结果进行调整。

另一个需要注意的重要事项:使用线程或线程池来处理事件仍然不会使异步,您只需使用多个线程来处理阻塞同步IO。我不熟悉SocketServer API,但一般情况下,如果它公开了一个自然异步API,则根本不需要额外的线程。例如,看一下内置支持异步IO的Netty

修改

正如您已澄清该操作是readData调用,并且只要应用程序处于活动状态,该操作就会运行,只需一个专用{{1这里会有更好的主意。

答案 1 :(得分:0)

异步I / O优于同步的主要(如果不是单一的)优点是少量线程可以支持大量连接。由于程序中的连接数很少(1),我建议使用专用线程。这使程序更简单,可维护,更高效。