Minha primeira apresentação sobre Elixir, para o evento Dev In Santos. As coisas essenciais que diferenciam Elixir de qualquer outra nova linguagem. Primeira palestra que eu subo com as anotações também (muito vídeo). #FullMetalAlchemist
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.
“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
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"]}
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")
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)
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
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
Javascript /
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
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).