ELIXIR OF LIFE
http://www.efeitmusic.com/efeitimages/Elixeroflife.jpg
ELIXIR OF LIFE
Fabio Akita http://www.efeitmusic.com/efeitimages/Elixeroflife.jpg
@akitaonrails
Intel1Processors1Transistor1Count 8,000,000,000
Duo-core + GPU Core i7 Broadwell-U
7,000,000,000
14 nm
6,000,000,000
18-core Xeon Haswell-E5 22 nm
5,000,000,000
15-core Xeon Ivy Bridge-EX
4,000,000,000
8-core Itanium Poulson
3,000,000,000
32 nm
Apple A8X 20 nm
2,000,000,000
Six-core Xeon 7400
1,000,000,000
Itanium 2 Intel 4004 10 µm
0 1965
1970
1975
Intel 80386 1980
1985
Pentium
Apple A8
Apple A7
0.8 µm
1990
1995
2000
2005
2010
2015
2020
Deveríamos estar em 9Ghz 16nm transistors quantum tunneling leakage, 1-3nm http://en.wikipedia.org/wiki/Quantum_tunnelling
EVENTOS!
Node + Express (8 x 200)
Node + Express (8 x 200)
Elixir + Phoenix (8 x 200)
Elixir + Phoenix (8 x 200)
Node + Express (1 x 10 + sleep(1))
Node + Express (1 x 10 + sleep(1))
Elixir + Phoenix (2 x 400 + sleep(1000))
Elixir + Phoenix (2 x 400 + sleep(1000))
LOW LATENCY
http://yarivsblog.blogspot.com.br/2008/05/erlang-vs-scala.html
Scala has two types of Actors: thread-based and event based. Thread based actors execute in heavyweight OS threads. They never block each other, but they don't scale to more than a few thousand actors per VM. Event-based actors are simple objects. They are very lightweight, and, like Erlang processes, you can spawn millions of them on a modern machine. The difference with Erlang processes is that within each OS thread, event based actors execute sequentially without preemptive scheduling. This makes it possible for an event-based actor to block its OS thread for a long period of time (perhaps indefinitely).
começo de novembro
Rackspace 15 GB I/O v1 - these machines have 15GB RAM and 4 cores. Rackspace kindly let us use 3 of these servers for our benchmarks free of charge.
OnMetal I/O which had 128GB RAM and showed 40 cores in htop.
começo de novembro
Rackspace 15 GB I/O v1 - these machines have 15GB RAM and 4 cores. Rackspace kindly let us use 3 of these servers for our benchmarks free of charge.
OnMetal I/O which had 128GB RAM and showed 40 cores in htop.
CASES
“Since cut-over of the first nodes in British Telecom's network in January 2002 only one minor fault has occurred, resulting in 99.9999999% availability.” “The network performance has been so reliable that there is almost a risk that our field engineers do not learn maintenance skills.” Bernt Nilsson - director of Ericsson’s Next Generation Systems program
http://www.erlang.org/download/armstrong_thesis_2003.pdf
BÁSICO …
iex --sname fabio --cookie secret_token
iex --sname akita --cookie secret_token
Node.list
Node.ping(:"akita@MacBook-Pro")
defmodule Greeting do
def say do
IO.puts "CALLED"
"Hello World from #{Node.self}"
end
end
:rpc.call(:"fabio@MacBook-Pro", Greeting, :say, [])
iex --name
[email protected] --cookie secret_token
iex --name
[email protected] --cookie secret_token
iex --sname fabio --cookie secret_token
iex --sname akita --cookie secret_token
Node.list
Node.ping(:"akita@MacBook-Pro")
defmodule Greeting do
def say do
IO.puts "CALLED"
"Hello World from #{Node.self}"
end
end
:rpc.call(:"fabio@MacBook-Pro", Greeting, :say, [])
iex --name
[email protected] --cookie secret_token
iex --name
[email protected] --cookie secret_token
PEER-TO-PEER NETWORKING
Matching
a = 20
defmodule Teste do
def teste do
a = 40
IO.puts("Hello #{a}")
end
end
IO.puts(a)
a = 20
^a = 40
[a, b, c] = [a, 2, 3]
{:ok, message} = {:ok, "world"}
{:ok, [hello: message]} = {:ok, [hello: "world"]}
Matching
a = 20
defmodule Teste do
def teste do
a = 40
IO.puts("Hello #{a}")
end
end
IO.puts(a)
a = 20
^a = 40
[a, b, c] = [a, 2, 3]
{:ok, message} = {:ok, "world"}
{:ok, [hello: message]} = {:ok, [hello: "world"]}
PATTERN MATCHING
Call by pattern
defmodule Greeting do
def hello([name: name]) do
"Hey, #{name}"
end
def hello([lastname: lastname]) do
"Hello, Mr #{lastname}"
end
end
Greeting.hello(name: "Fabio")
Greeting.hello(lastname: "Akita")
Call by pattern
defmodule Greeting do
def hello([name: name]) do
"Hey, #{name}"
end
def hello([lastname: lastname]) do
"Hello, Mr #{lastname}"
end
end
Greeting.hello(name: "Fabio")
Greeting.hello(lastname: "Akita")
CALL BY PATTERN
Spawn
self
send(self, :hello)
flush
send(self, :hello)
receive do
:hello -> IO.puts("hello")
end
defmodule Bar do
def say do
receive do
{:ok, message} ->
IO.puts("Hello #{message}")
say
end
end
end
Spawn
self
send(self, :hello)
flush
send(self, :hello)
receive do
:hello -> IO.puts("hello")
end
defmodule Bar do
def say do
receive do
{:ok, message} ->
IO.puts("Hello #{message}")
say
end
end
end
PROCESS (GREEN THREAD)
Green Thread = Co-Rotina que pode ser suspensa
2000 reduções
single thread por core/scheduler
1 run-queue
Processes
Process.list
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
end
end
end
pid = spawn(fn -> Foo.counter(2) end)
list = Enum.map((1..500_000), fn n ->
spawn(fn -> Foo.counter(n) end)
end)
Processes
Process.list
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
end
end
end
pid = spawn(fn -> Foo.counter(2) end)
list = Enum.map((1..500_000), fn n ->
spawn(fn -> Foo.counter(n) end)
end)
ASYNCHRONOUS
EXCEPTIONS
ESTADO IMUTAVEL
SEM ESTADO GLOBAL
ASYNCHRONOUS
EXCEPTIONS
ESTADO IMUTAVEL
SEM ESTADO GLOBAL
Trap Exits (http://eddwardo.github.io/elixir/links/2015/11/04/links-in-elixir/)
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
{:bla} ->
raise "I'm a bug!"
end
end
end
pid = spawn(fn -> Foo.counter(2) end)
Process.alive?(pid)
Process.link(pid)
Process.exit(pid, :kill)
pid = spawn(fn -> Foo.counter(2) end)
Trap Exits (http://eddwardo.github.io/elixir/links/2015/11/04/links-in-elixir/)
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
{:bla} ->
raise "I'm a bug!"
end
end
end
pid = spawn(fn -> Foo.counter(2) end)
Process.alive?(pid)
Process.link(pid)
Process.exit(pid, :kill)
pid = spawn(fn -> Foo.counter(2) end)
Observer/Schedulers
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
end
end
end
list = Enum.map((1..100_000), fn n ->
spawn(fn -> Foo.counter(n) end)
end)
Enum.each(list, fn pid -> Process.exit(pid, :kill) end)
defmodule Repeat do
Observer/Schedulers
defmodule Foo do
def counter(n) do
receive do
{:read, from} ->
send(from, n)
counter(n + 1)
end
end
end
list = Enum.map((1..100_000), fn n ->
spawn(fn -> Foo.counter(n) end)
end)
Enum.each(list, fn pid -> Process.exit(pid, :kill) end)
defmodule Repeat do
ACTORS!
GenServer Simple
defmodule Stack do
use GenServer
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
end
end
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer.call(pid, :pop)
GenServer.cast(pid, {:push, :world})
GenServer.cast(pid, {:push, :blabla})
GenServer.call(pid, :pop)
GenServer Simple
defmodule Stack do
use GenServer
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
end
end
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer.call(pid, :pop)
GenServer.cast(pid, {:push, :world})
GenServer.cast(pid, {:push, :blabla})
GenServer.call(pid, :pop)
defmodule Stack do
use GenServer
# Public API
def pop(server), do: GenServer.call(server, :pop)
def push(server, item), do: GenServer.cast(server, {:push, item})
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
end
end
{:ok, pid} = GenServer.start_link(Stack, ["John"])
Stack.push(pid, "Woo")
defmodule Stack do
use GenServer
# Public API
def pop(server), do: GenServer.call(server, :pop)
def push(server, item), do: GenServer.cast(server, {:push, item})
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
end
end
{:ok, pid} = GenServer.start_link(Stack, ["John"])
Stack.push(pid, "Woo")
GenServer Kill
defmodule Stack do
use GenServer
def start_link(state, opts \\ []) do
GenServer.start_link(__MODULE__, [state], name: __MODULE__)
end
def pop, do: GenServer.call(__MODULE__, :pop)
def push(item), do: GenServer.cast(__MODULE__, {:push, item})
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
GenServer Kill
defmodule Stack do
use GenServer
def start_link(state, opts \\ []) do
GenServer.start_link(__MODULE__, [state], name: __MODULE__)
end
def pop, do: GenServer.call(__MODULE__, :pop)
def push(item), do: GenServer.cast(__MODULE__, {:push, item})
# Callbacks
def handle_call(:pop, _from, [head|tail]) do
{:reply, head, tail}
end
def handle_cast({:push, item}, state) do
{:noreply, [item|state]}
Supervisor - Restart
defmodule StackSupervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init([]) do
children = [
worker(Stack, ["hello"])
]
supervise(children, strategy: :one_for_one)
end
end
StackSupervisor.start_link
Supervisor - Restart
defmodule StackSupervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init([]) do
children = [
worker(Stack, ["hello"])
]
supervise(children, strategy: :one_for_one)
end
end
StackSupervisor.start_link
SUPERVISOR TREE (supervisor - supervisees/workers)
OTP (Open Telecom Platform)
Phoenix - Observer
Applications - Micro Services
Phoenix - Observer
Applications - Micro Services
MICRO “YOCTO” SERVICES (Micro > Nano > Pico > Femto > Atto > Zepto > Yocto)
•
Map, Structs, Records, Comprehensions
•
Map, Structs, Records, Comprehensions
•
Testable Docs
•
Map, Structs, Records, Comprehensions
•
Testable Docs
•
TypeSpecs/Behaviors
•
Map, Structs, Records, Comprehensions
•
Testable Docs
•
TypeSpecs/Behaviors
•
Agents/Tasks/GenEvent
•
Map, Structs, Records, Comprehensions
•
Testable Docs
•
TypeSpecs/Behaviors
•
Agents/Tasks/GenEvent
•
Sigils/Macros/DSLs
•
Map, Structs, Records, Comprehensions
•
Testable Docs
•
TypeSpecs/Behaviors
•
Agents/Tasks/GenEvent
•
Sigils/Macros/DSLs
•
ETS/DETS/Mnesia
/
shared mutable global state Blocking Event Loop
Rust
/
Low Level Async in progress No coroutines
Go
Suture (OTP Clone)
goroutines sem ID shared mutable state static signatures
Scala
Akka (OTP Clone)
shared mutable state static signatures
Clojure
Pulsar / Quasar
Javascript
Almost Erlang-like Process JVM limitations
Go http://www.jerf.org/iri/post/2930
Scala http://yarivsblog.blogspot.com.br/2008/05/erlang-vs-scala.html
Clojure http://blog.paralleluniverse.co/2013/05/02/quasar-pulsar/
Scala has two types of Actors: thread-based and event based. Thread based actors execute in heavyweight OS threads. They never block each other, but they don't scale to more than a few thousand actors per VM. Event-based actors are simple objects. They are very lightweight, and, like Erlang processes, you can spawn millions of them on a modern machine. The difference with Erlang processes is that within each OS thread, event based actors execute sequentially without preemptive scheduling. This makes it possible for an event-based actor to block its OS thread for a long period of time (perhaps indefinitely).
“quase” …
Erlang:
DONE! (30 anos)
APRENDENDO
OBRIGADO
[email protected]