Procesy Elixir i przekazywanie komunikatów
Pozna Pan/Pani lekkie procesy języka Elixir, sposoby ich komunikacji oraz zasady współbieżności „niczego nie udostępniaj”.
Procesy Elixir i przekazywanie komunikatów to bezpłatna lekcja Elixir & Phoenix: Scalable Backend Development na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Elixir & Phoenix: Scalable Backend Development, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Elixir & Phoenix: Scalable Backend Development zawiera 4 lekcji w sumie.
Części tej lekcji nie zostały jeszcze przetłumaczone i są wyświetlane po angielsku.
Meet Elixir Processes
Elixir is built for concurrency, and processes are its core building blocks. Think of them as tiny, isolated programs running simultaneously.
Unlike operating system processes or threads, Elixir processes are incredibly lightweight. You can have hundreds of thousands, even millions, running on a single machine!
- Isolation: Each process has its own memory.
- Communication: They talk to each other by sending messages.
- Fault Tolerance: If one crashes, it doesn't bring down others.
Creating New Processes
We create a new Elixir process using the spawn function. It takes a function (often an anonymous function) that the new process will execute.
spawn returns a Process Identifier (PID), which is like an address for the new process.
defmodule MyModule do
def greet do
IO.puts "Hello from a new process!"
end
def run do
# Spawn a new process that calls MyModule.greet()
pid = spawn(MyModule, :greet, [])
IO.puts "Spawned process with PID: #{inspect(pid)}"
end
end
MyModule.run()Understanding Process IDs (PIDs)
A Process Identifier, or PID, is a unique reference to an Elixir process. It's how you address a specific process to send it messages.
Think of a PID like a phone number for a person. You dial their number to talk to them, and processes use PIDs to communicate.
- Every process has a unique PID.
- PIDs are essential for message passing.
- You can inspect a PID to see its internal representation.
Finding Your Own PID
Just like you can get the PID of a newly spawned process, any running process can find its own PID using the self() function.
This is crucial when a process needs to tell others how to send messages back to it.
defmodule PidDemo do
def show_self_pid do
IO.puts "My PID is: #{inspect(self())}"
end
def run do
IO.puts "Main process PID: #{inspect(self())}"
# Spawn a process to show its own PID
spawn(PidDemo, :show_self_pid, [])
:timer.sleep(100) # Give the spawned process time to run
end
end
PidDemo.run()Communicating with Messages
Elixir processes communicate by sending and receiving messages. This is the core of the 'share nothing' concurrency model.
Messages are simple Elixir terms (any data type) sent from one process to another's "mailbox."
send(pid, message): Putsmessageinto the mailbox of the process identified bypid.receive do ... end: Waits for messages in the current process's mailbox.
Answering Back
Let's see how a "client" process can send a message to a "server" process and receive a reply.
The server process uses a receive block to wait for and handle incoming messages. It then sends a reply back to the client's PID.
defmodule EchoServer do
def loop do
receive do
{:echo, client_pid, message} ->
send(client_pid, {:reply, message})
loop() # Continue looping to receive more messages
end
end
end
defmodule Client do
def run do
# Start the server process
server_pid = spawn(EchoServer, :loop, [])
IO.puts "Echo server started with PID: #{inspect(server_pid)}"
# Send a message to the server, including our own PID for reply
send(server_pid, {:echo, self(), "Hello, server!"})
IO.puts "Client sent 'Hello, server!' to #{inspect(server_pid)}"
# Wait for a reply
receive do
{:reply, message} ->
IO.puts "Client received reply: '#{message}'"
end
end
end
Client.run()Why Share Nothing Matters
Elixir processes embody the 'share nothing' principle. This means processes do not share memory or state directly.
Instead, they communicate exclusively through message passing. This design choice offers significant benefits:
- Isolation: Prevents one process from corrupting another's data.
- Concurrency: Easier to reason about and scale across multiple CPU cores.
- Fault Tolerance: A crash in one process doesn't affect others, making systems more robust.
Smart Message Handling
The receive block is incredibly powerful because it uses Elixir's pattern matching.
You can define different clauses within receive to match specific message structures, ignoring others until a match is found.
defmodule SmartReceiver do
def loop do
receive do
{:greet, name} ->
IO.puts "Hello, #{name}!"
loop()
{:farewell, name} ->
IO.puts "Goodbye, #{name}!"
loop()
:quit ->
IO.puts "Receiver quitting."
_ -> # Catch-all for unmatched messages
IO.puts "Received an unknown message."
loop()
end
end
def run do
receiver_pid = spawn(SmartReceiver, :loop, [])
send(receiver_pid, {:greet, "Alice"})
send(receiver_pid, "Just a string")
send(receiver_pid, {:farewell, "Bob"})
send(receiver_pid, :quit)
:timer.sleep(100) # Give processes time to finish
end
end
SmartReceiver.run()Keeping State with Recursion
Since processes don't share memory, how do they maintain state? Through recursion!
A process passes its current state as an argument to itself when it calls its loop function again. This creates an immutable, sequential flow of state changes.
defmodule Counter do
def loop(count) do
receive do
:increment ->
IO.puts "Incrementing to #{count + 1}"
loop(count + 1)
:get_count ->
IO.puts "Current count: #{count}"
loop(count)
:stop ->
IO.puts "Counter stopped at #{count}"
end
end
def run do
counter_pid = spawn(Counter, :loop, [0])
send(counter_pid, :increment)
send(counter_pid, :increment)
send(counter_pid, :get_count)
send(counter_pid, :stop)
:timer.sleep(100)
end
end
Counter.run()Processes & Messages Check
Consider the following Elixir code snippet:
defmodule Quiz do
def server_loop do
receive do
{:ping, client_pid} ->
send(client_pid, :pong)
server_loop()
end
end
def client_action(server_pid) do
send(server_pid, {:ping, self()})
receive do
:pong ->
IO.puts "Received pong!"
_ ->
IO.puts "Received something else."
end
end
def run do
server_pid = spawn(Quiz, :server_loop, [])
client_action(server_pid)
end
end
Quiz.run()What will be printed to the console when Quiz.run() is executed?
Your First Steps in Concurrency
Congratulations! You've taken a big step into Elixir's powerful concurrency model.
Here's a quick summary of what we covered:
- Elixir Processes: Lightweight, isolated execution units.
- PIDs: Unique identifiers for processes, used for addressing.
spawn&self(): Functions to create processes and get their PIDs.- Message Passing: The primary way processes communicate using
sendandreceive. - 'Share Nothing': Processes don't share memory, leading to robust and scalable systems.
- Pattern Matching: Used within
receiveto handle different message types. - State: Maintained through recursive function calls.
These fundamental concepts are the bedrock for building highly concurrent and fault-tolerant applications in Elixir!
Często zadawane pytania
Czy lekcja „Procesy Elixir i przekazywanie komunikatów” jest bezpłatna?
Tak — pełny tekst „Procesy Elixir i przekazywanie komunikatów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Elixir & Phoenix: Scalable Backend Development, przejdź na CoddyKit PRO. Kurs Elixir & Phoenix: Scalable Backend Development zawiera 4 lekcji w sumie.
Co nauczysz się w „Procesy Elixir i przekazywanie komunikatów”?
Pozna Pan/Pani lekkie procesy języka Elixir, sposoby ich komunikacji oraz zasady współbieżności „niczego nie udostępniaj”. Ćwiczysz Elixir & Phoenix: Scalable Backend Development z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Elixir & Phoenix: Scalable Backend Development?
Nie wymagamy żadnego doświadczenia. Elixir & Phoenix: Scalable Backend Development w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Procesy Elixir i przekazywanie komunikatów”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Elixir & Phoenix: Scalable Backend Development?
Tak. Każda lekcja Elixir & Phoenix: Scalable Backend Development zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Procesy Elixir i przekazywanie komunikatów
- Implementowanie zachowania GenServer
- Superwizory i struktura aplikacji
- Praca współbieżna z Task i Agent