Thinking in Scala vs Erlang
Keeping Erlang in mind, I've coded two months in Scala, I'm thinking something called "Scala vs Erlang", I wrote some benchmark code to prove me (the code and result may be available someday), and I'd like to do some gradually summary on it in practical aspect. These opinions may be or not be correct currently due to lacking of deep experience and understanding, but, anyway, I need to record them now and correct myself with more experiences and understanding got on both Scala and Erlang. Part I. Syntax Keeping Erlang in mind, I've coded two months in Scala, I'm thinking something called "Scala vs Erlang", I wrote some benchmark code to prove me (the code and result may be available someday), and I'd like to do some gradually summary on it in practical aspect. These opinions may be or not be correct currently due to lacking of deep experience and understanding, but, anyway, I need to record them now and correct myself with more experiences and understanding got on both Scala and Erlang. Part I. Syntax List comprehension Erlang: Lst = [1,2,3,4], [X + 1 || X <- Lst], lists:map(fun(X) -> X + 1 end, Lst) Scala: val lst = List(1,2,3,4) for (x <- lst) yield x + 1 lst.map{x => x + 1} lst.map{_ + 1} // or place holder Pattern match Erlang: case X of {A, B} when is_integer(A), A > 1 -> ok; _ -> error end, {ok, [{A, B} = H|T]} = my_function(X) Scala: x match { case (a:Int, b:_) if a > 1 => OK // can match type case _ => ERROR } val ("ok", (h@(a, b)) :: t) = my_function(x) List, Tuple, Array, Map, Binary, Bit Erlang: Lst = [1, 2, 3] %% List [0 | Lst] %% List concat {1, 2, 3} %% Tuple <<1, 2, "abc">> %% Binary %% no Array, Map syntax Scala: val lst = List(1, 2, 3) // List 0 :: lst // List concat (1, 2, 3) // Tuple Array(1, 2, 3) // Array Map("a" -> 1, "b" -> 2) // Map // no Binary, Bit syntax Process, Actor Erlang: the_actor(X) -> receive ok -> io:format("~p~n", [X]); I -> the_actor(X + I) %% needs to explicitly continue loop end. P = spawn(mymodule, the_actor, [0]) P ! 1 P ! ok Scala I: class TheActor(x:Int) extends Actor { def act = loop { react { case "ok" => println(x); exit // needs to explicitly exit loop case i:Int => x += i } } } val a = new TheActor(0) a ! 1 a ! "ok" Scala II: val a = actor { def loop(x:Int) = { react { case "ok" => println(x) case i:Int => loop(x + i) } } loop(0) } a ! 1 a ! "ok" Part II. Processes vs Actors Something I Erlang: Lightweight processes You can always (almost) create a new process for each new comer Scheduler treats all processes fairly Share nothing between processes Lightweight context switch between processes IO has been carefully delegated to independent processes Scala: Active actor is delegated to JVM thread, actor /= thread You can create a new actor for each new comer But the amount of real workers (threads) is dynamically adjusted according to the processing time The later comers may be in wait list for further processing until a spare thread is available Share nothing or share something upon you decision Heavy context switch between working threads IO block is still pain unless good NIO framework (Grizzly?) Something II Erlang: Try to service everyone simultaneously But may loss service quality when the work is heavy, may time out (out of service) Ideal when processing cost is comparable to context switching cost Ideal for small message processing in soft real-time Bad for massive data processing, and cpu-heavy work Scala: Try to service limited number of customers best first If can not service all, the later comers will be put in waiting list and may time out (out of service) It's difficult for soft real-time on all coming concurrent customers Ideal when processing cost is far more than context switching cost (context switch time is in μs on modern JVM) When will there be perfect NIO + Actor library? Posted: 2008-12-15 08:00 (Updated: 2010-04-02 22:26) Author: dcaoyuan Categories: Erlang Scala Comments 1. Martin -- 2008-12-16 08:00 Intertesting comparison, Caoyuan! Note that you can also do the explicit recursion style of actors in Scala. For instance like this: <pre> actor { def loop(i: Int) { react { case "ok" => println(i) case j: Int => loop(i + j) } } loop(0) } </pre> That brings the two examples in Erlang and Scala even closer together. 2. Caoyuan -- 2008-12-16 08:00 Martin, Perfect. I added your code to the content. 3. Hynek (Pichi) Vychodil -- 2008-12-18 08:00 Pattern matching in Erlang is can do more in default with less of code for me. <pre>{ok, [{A, B} = H|T]} = my_function(X)</pre> Is there equivalent in Scala that raising exception if no match? 4. Caoyuan -- 2008-12-18 08:00 Pichi, <pre>val ("ok", (h@(a, c)) :: t) = my_function(x)</pre> If no matched, will throw scala.MatchError? I've added this example to content. 5. Andy -- 2008-12-18 08:00 How is the performance of Scala compared to Erlang? Is there a certain level of concurrency at which one is faster than the other - e.g. Scala is faster at under 50 concurrent users but above that Erlang is faster? I'm very interested in seeing your benchmark results. 6. Caoyuan -- 2008-12-30 08:00 Andy, Briefly, If only do small message processing in each actor/process, especially in Binary, Erlang is faster than Scala; If do heavy work in each actor/process, for example, processing String/Text, Erlang is slow than Scala. Both can handle tons concurrent requests. |
|