Erlang Introduction: Processes, Concurrency and Actors2. Classification
• high-level
• general-purpose
• garbage-collected
• dynamically typed
• functional
• concurrent
Friday, February 10, 12
3. $ erl
Erlang R14B04 (erts-5.8.5)
[source] [64-bit] [smp:4:4] [rq:
4] [async-threads:0] [hipe]
[kernel-poll:false]
Eshell V5.8.5 (abort with ^G)
1>
Friday, February 10, 12
6. 1> 2 + 2.
4
2> 3 * 5.
15
3> 7 / 6.
1.1666666666666667
Friday, February 10, 12
7. 1> [].
[]
2> [1, 2, 3].
[1,2,3]
3> [101,104,63].
"eh?"
Friday, February 10, 12
8. 1> "a string".
"a string"
2>
[97,32,115,116,114,105,110,103].
"a string"
Friday, February 10, 12
9. 1> $H.
72
2> $e.
101
3> $l.
108
4> $o.
111
5> [$H, $e, $l, $l, $o].
"Hello"
Friday, February 10, 12
10. 1> true.
true
2> false.
false
3> true == false.
false
4> false == false.
true
5> true /= false.
true
Friday, February 10, 12
11. 1> atom.
atom
2> anotherAtom.
anotherAtom
3> 'One more atom?'.
'One more atom?'
Friday, February 10, 12
14. 1> {1,2,3}.
{1,2,3}
2> {16, "hello"}.
{16,"hello"}
3> {3.14, "Pi", {"foo", bar}}.
{3.14,"Pi",{"foo",bar}}
Friday, February 10, 12
16. 1> Variable = "value".
"value"
2> AnotherVariable = 128.
128
Friday, February 10, 12
17. 1> R = 5, Pi = 3.14.
3.14
2> Pi.
3.14
3> Pi * R * R.
78.5
Friday, February 10, 12
18. 1> X = 1.
1
3> X = 2.
** exception error: no match of right
hand side value 2
4> X = 1.
1
?!?!
Friday, February 10, 12
20. 1> X = 1, Y = 1.
1
2> X = Y.
???
Friday, February 10, 12
22. 1> X = 1.
1
2> X.
1
3> Y.
* 1: variable 'Y' is unbound
4> Y = 2.
2
5> Y.
2
Friday, February 10, 12
23. 1> User = {"John", "Doe", 35}.
...
2> {Name, Surname, Age} = User.
...
3> Name.
"John"
4> Age.
35
Friday, February 10, 12
24. 1> User = {"John", "Doe", 35}.
...
2> {Name, Surname} = User.
** exception error: no match of
right hand side value
{"John","Doe",35}
Friday, February 10, 12
25. 2> User = {"John", "Doe", 35}.
...
3> {Name, "Doe", 35} = User.
...
4> Name.
"John"
Friday, February 10, 12
26. 1> User = {"John", "Doe", 35}.
...
2> {Name, _, Age} = User.
...
3> Age.
35
4> Name.
"John"
Friday, February 10, 12
27. 1> _ = 1.
1
2> _.
* 1: variable '_' is unbound
5> _ = 3.
3
Friday, February 10, 12
28. 1> [Head | Tail] = [1,2,3].
[1,2,3]
2> Head.
1
3> Tail.
[2,3]
Friday, February 10, 12
29. 1> [1 | [2 | [3]]].
[1,2,3]
Friday, February 10, 12
31. -module(test).
-export([main/0]).
main() -> "Hello".
Friday, February 10, 12
33. -module(test).
-export([factorial/1]).
factorial(0) -> 1;
factorial(N) -> N * factorial(N - 1).
Friday, February 10, 12
34. $ erlc test.erl
$ erl
...
1> test:factorial(3).
6
2> test:factorial(5).
120
Friday, February 10, 12
35. -module(logger).
-export([log/1, log/2]).
log(Msg) -> {"info", Msg}.
log(Level, Msg) -> {Level, Msg}.
--------------------8<--------------------
1> logger:log("Some info message.").
{"info","Some info message."}
2> logger:log("error", "Kernel panic!").
{"error","Kernel panic!"}
Friday, February 10, 12
38. -module(test).
-export([fib/1]).
fib(0) -> 0;
fib(1) -> 1;
fib(N) when N > 0 ->
fib(N-1) + fib(N-2).
Friday, February 10, 12
39. test:fib(0).
0
3> test:fib(1).
1
5> test:fib(8).
21
6> test:fib(-23).
** exception error: no function
clause matching test:fib(-23)
Friday, February 10, 12
40. % Refactored factorial function:
factorial(0) -> 1;
factorial(N)
when is_integer(N) and (N > 0) ->
N * factorial(N - 1);
factorial(_) ->
{error, "Invalid argument"}.
Friday, February 10, 12
41. 7> factorial:factorial(3).
6
8> factorial:factorial(0).
1
9> factorial:factorial(-1).
{error,"Invalid argument"}
10> factorial:factorial("a").
{error,"Invalid argument"}
Friday, February 10, 12
42. Concurrency
• any function can become a process
• process is a function executing in
parallel
• process shares nothing with other
processes
Friday, February 10, 12
43. Processes/Actors
• processes are extremely lightweight and
fast
• ~15 seconds to spawn 100k processes on
my machine (MacBook Pro 8.1, OSX)
Friday, February 10, 12
47. -module(actor).
-export([loop/0]).
loop() ->
receive
die -> io:format("Exiting~n")
end.
Friday, February 10, 12
48. 2> Pid = spawn(actor, loop, []).
<0.40.0>
3> is_process_alive(Pid).
true
4> Pid ! die.
Exiting
die
5> is_process_alive(Pid).
false
Friday, February 10, 12
49. loop() ->
receive
die ->
io:format("Exiting~n");
Msg ->
io:format("Got: ~p~n", [Msg])
end.
Friday, February 10, 12
50. 2> Pid = spawn(actor, loop, []).
...
3> is_process_alive(Pid).
true
4> Pid ! "Hello".
Got: "Hello"
...
5> is_process_alive(Pid).
false
Friday, February 10, 12
51. loop() ->
receive
die ->
io:format("Exiting~n");
Msg ->
io:format("Got: ~p~n", [Msg]),
loop()
end.
Friday, February 10, 12
52. 2> Pid = spawn(actor, loop, []).
...
3> Pid ! "Hello".
Got: "Hello"
4> is_process_alive(Pid).
true
5> Pid ! "Hello again!".
Got: "Hello again!"
6> is_process_alive(Pid).
true
7> Pid ! die.
Exiting
8> is_process_alive(Pid).
false
Friday, February 10, 12
54. -module(counter).
-export([loop/1]).
loop(N) ->
receive
increment -> loop(N + 1);
decrement -> loop(N - 1);
print ->
io:format("Current counter value: ~w~n", [N]),
loop(N)
end.
Friday, February 10, 12
55. 2> Counter = spawn(counter, loop, [0]).
...
3> Counter ! increment.
...
4> Counter ! increment.
...
5> Counter ! print.
Current counter value: 2
...
6> Counter ! decrement.
...
7> Counter ! print.
Current counter value: 1
Friday, February 10, 12
56. 2> C1 = spawn(counter, loop, [0]).
<0.40.0>
3> C2 = spawn(counter, loop, [10]).
<0.42.0>
4> C1 ! increment, C1 ! increment, C1 ! print.
Current counter value: 2
5> C2 ! decrement, C2 ! print.
Current counter value: 9
Friday, February 10, 12
60. s erl -sname slave -setcookie '123!@#qwe'
...
(slave@Serhiys-MacBook-Pro)1> node().
'slave@Serhiys-MacBook-Pro'
Friday, February 10, 12
61. $ erl -sname master -setcookie '123!@#qwe'
...
(master@Serhiys-MacBook-Pro)1>
net_adm:ping('slave@Serhiys-MacBook-Pro').
pong
(master@Serhiys-MacBook-Pro)3>spawn('slave@Serhiys-
MacBook-Pro', factorial, factorial, [100]).
933262154439441526816992388562667004907159682643816
214685929638952175999932299156089414639761565182862
536979208272237582511852109168640000000000000000000
00000
<6619.52.0>
Friday, February 10, 12
63. -module(actor).
-export([loop/0]).
loop() ->
receive
N ->
S = math:sqrt(N),
io:format("sqrt(~p) = ~p~n", [N,S]),
loop()
end.
Friday, February 10, 12
64. 2> Pid = spawn(actor, loop, []).
...
3> Pid ! 4.
sqrt(4) = 2.0
...
5> Pid ! "a".
=ERROR REPORT==== 24-Jan-2012::14:06:02 ===
Error in process <0.40.0>
...
6> is_process_alive(Pid).
false
Friday, February 10, 12
65. Supervisors
• supervisors monitor processes and take
actions on exit signals
• process linking does the trick
Friday, February 10, 12
66. start() -> spawn(actor, restarter, []).
restarter() ->
process_flag(trap_exit, true),
Pid = spawn_link(actor, loop, []),
register(myActor, Pid),
receive
{'EXIT', _Pid, _Reason} ->
io:format("Process crashed. Restarting~n"),
restarter()
end.
Friday, February 10, 12
67. 2> actor:start().
3> myActor ! 4.
sqrt(4) = 2.0
4> myActor ! "foo".
Process crashed. Restarting
=ERROR REPORT====
Error in process <0.41.0> ...
5> is_process_alive(whereis(myActor)).
true
6> myActor ! 9.
sqrt(9) = 3.0
Friday, February 10, 12
69. Simplicity
• You just learned
• ~70% of Erlang syntax
• most major abstractions: modules,
functions and processes
• most of the core data types
Friday, February 10, 12
70. Complexity
• Erlang/OTP is a complex framework
• Learning it takes time and practice
Friday, February 10, 12
71. Bad Stuff
• syntax
• Strings
• code organization
• libraries
• underestimated complexity of OTP and
concurrent applications generally
• your colleagues will not understand you :)
Friday, February 10, 12
72. Practical Application
• Notable uses:
• Facebook (Chat)
• CouchDB
• RabbitMQ
• Membase
• Riak
Friday, February 10, 12
75. Erlang getting started guide:
http://www.erlang.org/doc/getting_started/intro.html
Friday, February 10, 12
78. [$Q, $u, $e, $s, $t, $i, $o, $n, $s, $?].
Friday, February 10, 12