@elixirlang / elixir-lang.org
Tooling
current_process = self()
# Spawn an Elixir process (not an operating system one!)
spawn_link(fn ->
send current_process, {:msg, "hello world"}
end)
# Block until the message is received
receive do
{:msg, contents} -> IO.puts contents
end
Due to their lightweight nature, it is not uncommon to have hundreds of thousands of processes running concurrently on the same machine.
Isolation allows processes to be garbage collected independently, reducing system-wide pauses, and using all machine resources as efficiently as possible (vertical scaling).
Processes are also able to communicate with other processes running on different machines in the same network. This provides the foundation for distribution, allowing developers to coordinate work across multiple nodes (horizontal scaling).
children = [
TCP.Pool,
{TCP.Acceptor, port: 4040}
]
Supervisor.start_link(children, strategy: :one_for_one)
A supervisor is a process which supervises other processes, which we refer to as child processes. Supervisors are used to building a hierarchical process structure called a supervision tree. Supervision trees provide fault-tolerance and encapsulate how our applications start and shutdown.
Supervisor strategies
:one_for_one
:one_for_all
:rest_for_one
:simple_one_for_one
Elixir ships with a great set of tools to ease development. Mix is a build tool that allows you to easily create projects, manage tasks, run tests and more
$ mix new my_app
$ cd my_app
$ mix test
.
Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures
Tools like IEx (Elixir’s interactive shell) are able to leverage many aspects of the language and platform to provide auto-complete, debugging tools, code reloading, as well as nicely formatted documentation:
$ iex
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex> h String.trim # Prints the documentation for function
iex> i "Hello, World" # Prints information about the given data type
iex> break! String.trim/1 # Sets a breakpoint in the String.trim/1 function
iex> recompile # Recompiles the current project on the fly
iex> :crypto.hash(:md5, "Using crypto from Erlang OTP")
<<192, 223, 75, 115, ...>>
# Egar vs Lazy
iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000
# Pipe vs no pipe
iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000
iex> Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))
7500000000
$ mix new myproject_umbrella --umbrella
* creating .gitignore
* creating README.md
* creating mix.exs
* creating apps
* creating config
* creating config/config.exs
$ cd myproject_umbrella/apps
$ mix new myproject_api_server --sup
* creating .gitignore
* creating README.md
* creating mix.exs
* creating apps
* creating config
* creating config/config.exs
* creating test
$ mix new myproject_data_processing --sup
* creating .gitignore
* creating README.md
* creating mix.exs
* creating lib
* creating config
* creating config/config.exs
* creating test
+ myproject_umbrella
+ apps
+ myproject_api_server
+ myproject_data_processing
$ mix release.init # As one monolith app
release :myproject do
set version: "0.1.0"
set applications: [:myproject_server_api, :myproject_data_processing]
end
$ mix release.init --release-per-app # release each sub app individually
release :myproject_server_api do
set version: "0.1.0"
set applications: [:myproject_server_api]
end
release :myproject_data_processing do
set version: "0.1.0"
set applications: [:myproject_data_processing]
end
@tian_yi_wang