0
votes

I'm learning the scala. I am very confused about the difference between actor and goroutine.

As known, the concurrency unit of golang is goroutine, and the concurrency model is very special and elegant in my opinion:

  • CPU bound task

The runtime scheduler would preempt long-running coroutine at best effort, e.g. check preemption at function call, so that the long-running coroutine would not occupy the system thread too long

  • event driven call

For example, on Linux, all types of events which could be managed by epoll, e.g. socket connect, would yield the goroutine and resume it when call finished later. When the goroutine yields, the holding thread would be released to handle next ready goroutine

  • cgo calls

Such calls would exclusively occupy one system thread until the call returns.

How to handle all these types of calls in scala actor?

The scala reuses and depends on the JDK to access low-level syscalls, right? e.g. network socket. And some high-level libraries are also reused in scala, e.g. JDBC. The Java's concurrency model is threading (system threads), and all those calls in Java would block the thread until call returns. So how to encapsulate them in actor? Does actor perform different from goroutine?

Looking forward to any professional answers! Thanks!

Edit:

I search some documents, and I guess the answer maybe:

  • CPU bound task

no preemption provided in scala

  • event driven call

As Akka is integrated into scala, so either use Akka async wrapped libraries (e.g. Akka TCP) or use future?

  • cgo calls

???

I change the title of this post. I already understand the style difference between actor and goroutine, and I just care about how to handle different types of calls in actor, just like gorotuine.

Edit:

Sorry, finally I find out what's exactly my question:

could we yield/resume actor just like goroutine?

Or actor just a scheduled computation piece which should run from start to end? i.e. the whole message processing could not be interrupted.

And because of the threading model in Java, I think it lacks of low-level support of blocking calls based on coroutine, right? e.g. socket read, if blocks, yield the coroutine, when new data read to read, resume the coroutine; while it's transparent to the programmer, all you need to write is socket.read(). As known, in Java, this whole procedure is based on system thread, the traditional way just like C.

1
Yes, I read those posts. But they do not explain how to handle the calls as I mentioned above in actor.kingluo

1 Answers

2
votes

If all you want to know is how to handle IO call, Future is considered more idiomatic in scala.

Akka is good when you have a hierarchy model, or you want any sophisticated fault recovery mechanism, but if all you want to do is IO, Future is sufficient, and much simpler.

Also, IO call can be either blocking or non-blocking (at thread level), you need to handle it separately. Fortunately it is as easy as

Future {
  // non-blocking IO call
} 

import scala.concurrent.blocking
Future {
  blocking {
    ... some blocking IO call
  }
}

If you need to do a lot of IO blocking call, use a separate ExecutionContext

And DO NOT wrap CPU bound task inside a Future, CPU bound means your program will not benefit because of Future. If you need Future to match interface, use

Future.successful {
  // computation
}

I learn most of these details from

  1. https://github.com/alexandru/scala-best-practices/blob/master/sections/4-concurrency-parallelism.md
  2. http://docs.scala-lang.org/overviews/core/futures.html

Edit 1: The questions was updated, this edit try to answer the new question

Q: Could we yield/resume actor?

A: I am not very sure if I understand correctly, may I know why do you want to yield and resume an actor? It seems like you wish to control the low-level processing details of runtime, which I believe is not achievable for actor.

Actor is reactive, means it does something whenever you send it a message, and that's all, you have no control over how things are executed, same actor might even run on different threads.

Typically if we need asynchronous operation, we will wrap the operation in a Future, but future does not automatically make the problem goes away, if your operation wrapped in Future is blocking the thread, it will still block, but wrapping in Future makes your code asynchronous, ie, the next line of code can be run without waiting previous operation to return.

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import java.lang.Thread

Future {
  Thread.sleep(1000)
  println("Woke up")
}

println("Sleeping")

The outcome will be

Sleeping
Woke up