6

I want to build a simple server in Scala 2.11 that listens on a socket. It should asynchronously read data from the socket and pass the data into a Observable from RxScala.

I have a Java ServerSocket from which the data should be read with the method readData which is blocking. This method is started once and runs until the whole program stops:

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

I found two different ways to avoid blocking the whole program, when the data is read from the socket:

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

and

Future {
  blocking {
    readData(server)
  }
}

Because there is no return value wrapped in the Future, which can then be passed to other tasks, the only task for the Future is to make the computation non blocking. So I wonder if there are any larger differences between these approaches? Looking into implementation of the Future it looks like it also creates and runs a Runnable with the given block. So is one of these approaches preferable if one has a single and forever/long running task without a result?

nicoring
  • 633
  • 5
  • 12

2 Answers2

6

So is one of these approaches preferable if one has a long or forever running task without a result?

The two examples differ in the fact that the former allocates a new thread per requests, and the second example implicitly uses Scala's default ExecutionContext which is backed by a ForkJoinPool, which is basically a pool of threads that can scale up/down as needed.

One needs to remember that a thread doesn't come for free, it needs to allocate a stack (which varies based on the OS), system calls that need to be made to register that thread, etc (you can read more in Why is creating a Thread said to be expensive?).

Generally, I'd go with the latter "naive" approach of using a Future with the blocking which utilizes the global ExecutionContext. Most importantly, I'd benchmark my code to make sure I am satisfied with the way the code is behaving, and then make adjustments based on those findings.

Another important thing to note: Using a thread or a threadpool to process events still doesn't make ot asynchronous, you're simply using multiple thread to process blocking sync IO. I'm not familiar with the SocketServer API, but in general if it exposes a naturally async API, there need not be extra threads at all. For example, take a look at Netty which has built in support for async IO.


Edit

As you've clarified that the operation is a single invocation of readData, and the operation runs for as long as the application is alive, a single dedicated Thread would be a better idea here.

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • I may be wrong, but I only start one Thread/Future thus there should be no need for pooling. So there is only one connection on this Socket. – nicoring Jul 28 '16 at 09:23
  • @nico If `readData` isn't a repetitive operation, you'll be fine with either. If the operation is rather long running, you might even be better off with a dedicated thread – Yuval Itzchakov Jul 28 '16 at 10:05
  • Ok, so that was exactly what I was wondering about, seems like my question was not precise enough. I have **one long running operation**, which i put either in a Thread or a Future. – nicoring Jul 28 '16 at 15:16
  • @nico It is traditionally known that operations inside a threadpool shouldn't be long running. What is long running you ask? well there isn't really an agreement on that. Generally, let's say something that takes more than 200-400ms to complete. If so, use a dedicated thread. – Yuval Itzchakov Jul 28 '16 at 15:19
  • Since my operation runs as long as the program runs, a dedicated Thread should be the best solution and the answer to my question, thanks! – nicoring Jul 28 '16 at 15:31
0

The main (if not single) advantage of asynchronous I/O over synchronous is that small number of threads can support large number of connections. Since the number of connections in your program is small (1), I recommend to use dedicated thread. This make program more simple, maintainable, and more efficient.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38