请解释Elixir中Supervisor与DynamicSupervisor的区别
Supervisor vs DynamicSupervisor in Elixir: Key Differences
Hey there! If you’ve worked with Elixir’s OTP ecosystem, you know supervisors are the backbone of fault-tolerant systems. But Supervisor and DynamicSupervisor serve very distinct purposes—let’s break down their core differences with practical context.
1. Primary Use Case
- Supervisor: Built for static child processes—processes you know need to exist as soon as your application (or supervisor) starts. Think core services like database connection pools, long-running cache workers, or background job processors that run continuously.
- DynamicSupervisor: Designed for dynamic, on-demand child processes—processes you create and destroy at runtime based on application needs. Examples include handling individual user requests, spawning temporary task workers, or scaling processes to match real-time load.
2. Child Specification Setup
- Supervisor: Requires you to define all child process specifications upfront in the
init/1callback. When the supervisor starts, it immediately launches all these children.
Example snippet:defmodule MyApp.CoreSupervisor do use Supervisor def start_link(opts) do Supervisor.start_link(__MODULE__, opts, name: __MODULE__) end @impl true def init(_opts) do children = [ {MyApp.DBConnectionPool, size: 10}, MyApp.CacheWorker ] Supervisor.init(children, strategy: :one_for_one) end end - DynamicSupervisor: No upfront child specs. You pass the child specification when you want to start a new process via
DynamicSupervisor.start_child/2. The supervisor starts empty and only spawns children as needed.
Example snippet:defmodule MyApp.DynamicWorkerSupervisor do use DynamicSupervisor def start_link(opts) do DynamicSupervisor.start_link(__MODULE__, opts, name: __MODULE__) end @impl true def init(_opts) do DynamicSupervisor.init(strategy: :one_for_one) end # Call this at runtime to spawn a new worker def spawn_worker(task_data) do child_spec = {MyApp.TempTaskWorker, data: task_data} DynamicSupervisor.start_child(__MODULE__, child_spec) end end
3. Restart Strategy Focus
Both support OTP restart strategies, but their intended usage differs:
- Supervisor: Works with all standard strategies (
:one_for_one,:one_for_all,:rest_for_one,:simple_one_for_one). The strategy applies to all static children—for example,:one_for_allrestarts every child if any one crashes (great for interdependent services). - DynamicSupervisor: Almost exclusively uses the
:one_for_onestrategy (it’s the default). Since dynamic children are independent by nature, restarting just the crashed process makes the most sense. Other strategies are rarely used here because dynamic processes typically don’t have hard dependencies on each other.
4. Startup Behavior
- Supervisor: Starts all its child processes immediately when the supervisor itself starts. If any child fails to start, the supervisor will terminate and propagate the error (unless you adjust the child spec’s
restartoption). - DynamicSupervisor: Starts with zero child processes. It only spawns children when explicitly told to via
start_child/2or similar functions.
5. Child Process Tracking
- Supervisor: Since children are static, you often register them with a name (via the child spec) so you can easily reference them later (e.g.,
GenServer.call(MyApp.CacheWorker, :get)). - DynamicSupervisor: Children are usually anonymous (unless you explicitly register a name in their child spec). To track dynamic processes, you’ll typically use tools like
Registryto map process identifiers to your business context (like user IDs or task IDs).
Quick Rule of Thumb
Use Supervisor when you know exactly which processes need to run at application startup. Use DynamicSupervisor when you need to create processes on the fly, and the number of processes varies during runtime.
内容的提问来源于stack exchange,提问作者Nuno_Coletiv
相关产品推荐
相关产品推荐

