Scala Future vs Thread 长时间 运行 任务没有结果
Scala Future vs Thread for a long running task without result
我想在 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)
}
}
因为没有 return 包装在 Future 中的值可以传递给其他任务,所以 Future 的唯一任务是使计算成为非阻塞的。所以我想知道这些方法之间是否有更大的差异?查看 Future 的实现,看起来它还使用给定的块创建并运行一个 Runnable。那么,如果只有一项 forever/long 运行 任务没有结果,那么这些方法中的一种是否更可取?
So is one of these approaches preferable if one has a long or forever
running task without a result?
这两个示例的不同之处在于前者为每个请求分配一个新线程,而第二个示例隐式使用 Scala 的默认值 ExecutionContext
,它由 ForkJoinPool
支持,这基本上是一个可以根据需要扩展 up/down 的线程池。
需要记住线程不是免费的,它需要分配一个堆栈(根据OS而变化),需要进行系统调用来注册该线程,等(您可以在 Why is creating a Thread said to be expensive? 中阅读更多内容)。
通常,我会采用后一种 "naive" 方法,即使用 Future
和 blocking
,后者利用全局 ExecutionContext
。最重要的是,我会对我的代码进行基准测试 以确保我对代码的行为方式感到满意,然后根据这些发现进行调整。
另一个需要注意的重要事项:使用线程或线程池来处理事件仍然不会异步,你只是使用多线程来处理阻塞同步IO .我不熟悉 SocketServer API,但一般来说,如果它公开自然异步 API,则根本不需要额外的线程。例如,看看 Netty 内置了对异步 IO 的支持。
编辑
正如您所阐明的那样,该操作是 单次 调用 readData
,并且只要应用程序处于活动状态,该操作就会运行,一个专用的Thread
在这里会是一个更好的主意。
异步 I/O 相对于同步的主要(如果不是唯一)优势是少量线程可以支持大量连接。由于您程序中的连接数很少(1),我建议使用专用线程。这使程序更简单、可维护且更高效。
我想在 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)
}
}
因为没有 return 包装在 Future 中的值可以传递给其他任务,所以 Future 的唯一任务是使计算成为非阻塞的。所以我想知道这些方法之间是否有更大的差异?查看 Future 的实现,看起来它还使用给定的块创建并运行一个 Runnable。那么,如果只有一项 forever/long 运行 任务没有结果,那么这些方法中的一种是否更可取?
So is one of these approaches preferable if one has a long or forever running task without a result?
这两个示例的不同之处在于前者为每个请求分配一个新线程,而第二个示例隐式使用 Scala 的默认值 ExecutionContext
,它由 ForkJoinPool
支持,这基本上是一个可以根据需要扩展 up/down 的线程池。
需要记住线程不是免费的,它需要分配一个堆栈(根据OS而变化),需要进行系统调用来注册该线程,等(您可以在 Why is creating a Thread said to be expensive? 中阅读更多内容)。
通常,我会采用后一种 "naive" 方法,即使用 Future
和 blocking
,后者利用全局 ExecutionContext
。最重要的是,我会对我的代码进行基准测试 以确保我对代码的行为方式感到满意,然后根据这些发现进行调整。
另一个需要注意的重要事项:使用线程或线程池来处理事件仍然不会异步,你只是使用多线程来处理阻塞同步IO .我不熟悉 SocketServer API,但一般来说,如果它公开自然异步 API,则根本不需要额外的线程。例如,看看 Netty 内置了对异步 IO 的支持。
编辑
正如您所阐明的那样,该操作是 单次 调用 readData
,并且只要应用程序处于活动状态,该操作就会运行,一个专用的Thread
在这里会是一个更好的主意。
异步 I/O 相对于同步的主要(如果不是唯一)优势是少量线程可以支持大量连接。由于您程序中的连接数很少(1),我建议使用专用线程。这使程序更简单、可维护且更高效。