Share
Embed
Transcript
37 slides
-
План доклада • Быстро пройдемся по базовым вещам • Посмотрим,
чем Elixir отличается от других языков • А потом поговорим об инфраструктуре вокруг языка -
Elixir • Написан Jose Valim (Rails Core Dev) в 2012
году • Основывается на BEAM -
Типы данных iex> 1 # integer iex> 1.0 # float
iex> true # boolean iex> :atom # atom iex> "elixir" # string (unicode!) iex> [1, 2, 3] # list iex> {1, 2, 3} # tuple iex> %{a: 1} # map iex> [key: v] # keyword list -
Приятные фичи • Pattern matching [1 | tail] = [1,
2, 3] #=> [1, 2, 3] tail #=> [2, 3] • Pipes "Elixir rocks" |> String.upcase |> String.split #=> ["ELIXIR", "ROCKS"] • Макросы -
parent = self() #=> PID<0.80.0> spawn fn -> send(parent, {:hello,
self()}) end #=> PID<0.83.0> receive do {:hello, pid} -> "Got hello from #{inspect pid}" end #=> "Got hello from #PID<0.83.0>" Процессы - изолированные, параллельные, легковесные -
Уже готовые обертки • Agent - простая обертка над процессом
с состоянием • GenServer - "generic process", инкапсулирует работу с состоянием, добавляют возможность использовать sync и async методы • GenEvent - позволяет работать с событиями • Task - позволяет запустить процесс, а потом получить его результат -
Обработка ошибок try do raise "Big Bad Error" rescue e
-> IO.inspect(e) end #=> %RuntimeError{message: "Big Bad Error"} try do throw "Big Bad Throwable Error" catch e -> IO.inspect(e) end #=> "Big Bad Throwable Error" А еще все умрет, если умрет связанный (linked) процесс... -
defmodule Stack do use GenServer def start_link(state, opts \\ [])
do GenServer.start_link(__MODULE__, state, opts) end def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, h}, t) do {:noreply, [h | t]} end end Наше приложение -
Строим supervisor tree # Import helpers for defining supervisors import
Supervisor.Spec # Supervise the Stack server which will be started with # a single argument [:hello] and the default registered # name of MyStack. children = [ worker(Stack, [[:hello], [name: MyStack]]) ] # Start the supervisor with our child {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one) -
Используем приложение GenServer.call(MyStack, :pop) #=> :hello GenServer.cast(MyStack, {:push, :world}) #=>
:ok GenServer.call(MyStack, :pop) #=> :world GenServer.call(MyStack, :pop) #=> ??? #=> BOOM!!! -
source = File.read!("source.txt") #=> "roses are red\nviolets are blue\n\n" source
|> String.split("\n") |> Enum.flat_map(&String.split/1) |> Enum.reduce(%{}, fn(word, map) -> Map.update(map, word, 1, &(&1 + 1)) end) Жадный подход -
Ленивый подход File.stream!("source.txt", [], :line) |> Stream.flat_map(&String.split/1) |> Enum.reduce(%{}, fn(word,
map) -> Map.update(map, word, 1, &(&1 + 1)) end) -
Асинхронный подход File.stream!("source.txt", [], :line) |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |>
Flow.partition() # the magic happens here |> Flow.reduce(fn -> %{} end, fn(word, map) -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) -
Результаты • На маленьком объеме данных побеждает "жадный подход" (более
чем в 19 раз) • На средних и больших побеждает Flow (от 3 раз) • https://github.com/sobolevn/fpconf_elixir -
mix • Встроенный build-tool, который выполняет все необходимые действия •
Управляет зависимостями (как bundler) • Запускает задачи (как manage.py, rake) • Управляет конфигурацией -
4.0GHZ Core i7 (quad core), 32GB RAM Framework Throughput (req/
s) Latency (ms) Consistency (σ ms) Gin 59001.07 1.84 1.35 Phoenix 31417.81 3.52 3.50 Express Cluster 26244.35 3.92 3.25 Sinatra 8334.84 7.46 3.38 Express 9477.14 10.56 1.39 Rails 3452.58 17.96 7.73 -
Ecto defmodule Weather do use Ecto.Schema import Ecto.Query schema "weather"
do field :city, :string field :temp_lo, :integer field :temp_hi, :integer end def keyword_query do query = from w in Weather, where: w.city == "Moscow" and w.temp_lo > 0, select: w Repo.all(query) end end -
Когда использовать? • У вас высоконагруженное приложение • У вас
есть задачи, которые нужно выполнять асинхронно / параллельно • Вам крайне важна отказоустойчивость -
Материалы • Keynote by Jose Valim: https://www.youtube.com/watch?v=srtMWzyqdp8 • The Road
to 2 Million Websocket Connections in Phoenix: https:// www.youtube.com/watch?v=c6JcVwbOGXc • Processing 2.7 million images with Elixir: https://www.youtube.com/watch? v=xoNRtWl4fZU • Elixir on the Web: Raising Phoenix: https://www.youtube.com/watch? v=h4z7WnMLXKI • benchee: https://github.com/PragTob/benchee • Phoenix benchmarks: https://github.com/mroth/phoenix-showdown • Код из презентации: https://github.com/sobolevn/fpconf_elixir