You are on page 1of 106

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


Apple A8

1,000,000,000 Itanium 2
Apple A7
Intel 4004 Pentium
10 µm Intel 80386
0.8 µm
0
1965 1970 1975 1980 1985 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 fabio@192.168.1.4 --cookie secret_token

iex --name akita@192.168.1.4 --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 fabio@192.168.1.4 --cookie secret_token

iex --name akita@192.168.1.4 --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
Javascript /
Blocking Event Loop

Low Level
Rust / Async in progress
No coroutines

goroutines sem ID
Suture
Go shared mutable state
(OTP Clone)
static signatures

Akka shared mutable state


Scala
(OTP Clone) static signatures

Almost Erlang-like Process


Clojure Pulsar / Quasar
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

become@codeminer42.com

You might also like