Elixir 프로세스와 메시지 전달
가벼운 Elixir 프로세스와 프로세스 간 통신 방법, 그리고 '공유하지 않음' 동시성의 원리를 배웁니다.
Elixir 프로세스와 메시지 전달은(는) CoddyKit의 무료 Elixir & Phoenix: Scalable Backend Development 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Elixir & Phoenix: Scalable Backend Development 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Elixir & Phoenix: Scalable Backend Development 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
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!
자주 묻는 질문
“Elixir 프로세스와 메시지 전달” 강의는 무료인가요?
네 — “Elixir 프로세스와 메시지 전달” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Elixir & Phoenix: Scalable Backend Development 강의 전체를 잠금 해제할 수 있습니다. Elixir & Phoenix: Scalable Backend Development 강의에는 총 4개의 강의가 포함되어 있습니다.
“Elixir 프로세스와 메시지 전달”에서 뭘 배우나요?
가벼운 Elixir 프로세스와 프로세스 간 통신 방법, 그리고 '공유하지 않음' 동시성의 원리를 배웁니다. 브라우저에서 직접 실행하는 실습 코드로 Elixir & Phoenix: Scalable Backend Development을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Elixir & Phoenix: Scalable Backend Development을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Elixir & Phoenix: Scalable Backend Development은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“Elixir 프로세스와 메시지 전달” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Elixir & Phoenix: Scalable Backend Development 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Elixir & Phoenix: Scalable Backend Development 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- Elixir 프로세스와 메시지 전달
- GenServer 동작 구현
- 감독자와 애플리케이션 구조
- Task와 Agent를 사용한 동시 작업