0Pricing
Erlang OTP: Distributed & Fault-Tolerant Systems Programming · 강의

동적 프로세스 관리

감독자 내에서 자식 프로세스를 동적으로 시작하고 중지하는 방법을 숙달하여 적응력 있고 자원을 효율적으로 사용하는 시스템을 구축합니다.

동적 프로세스 관리은(는) CoddyKit의 무료 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Dynamic Processes Overview

In Erlang, not all processes need to be started when your application first boots. Sometimes, you need processes that are created and destroyed on demand.

These are called dynamic processes, and they are crucial for building adaptable and resource-efficient systems. Think of them as temporary workers that supervisors can hire and fire as needed.

Why Dynamic Management?

Dynamic process management offers several key advantages:

  • Resource Efficiency: Only start processes when they are actually needed, saving memory and CPU.
  • Adaptability: Respond to varying loads by scaling up or down the number of workers.
  • On-Demand Tasks: Ideal for handling transient tasks like a new client connection, a file conversion request, or a single database query.

This contrasts with static children, which are always part of the supervisor's initial setup.

The `simple_one_for_one` Strategy

To manage dynamic children, supervisors often employ the simple_one_for_one restart strategy. This strategy is specifically designed for supervisors that will dynamically add children after startup.

  • It allows you to add children without pre-defining them in the supervisor's init/1 function.
  • Each dynamically added child is treated as a unique entity, even if they share the same underlying module.
  • If a dynamic child crashes, simple_one_for_one will restart only that child, not all of them.

Starting Dynamic Children

You start a dynamic child process using the supervisor:start_child/2 function. It takes two arguments:

  • SupRef: The name or PID of the supervisor.
  • ChildSpec: A map (or a list of tuples in older Erlang) describing the child process.

This function returns {ok, ChildPid} or an error if the child couldn't be started.

Dynamic Child Specification

A ChildSpec for a dynamic child is similar to a static one, but the id field is crucial for distinguishing instances. Here's a typical structure:

  • id: A unique atom or term to identify this specific child instance (e.g., client_123).
  • start: A tuple {Module, Function, Args} to call for starting the child (e.g., {gen_server, start_link, [{local, TaskId}, ?MODULE, [], []]}).
  • type: Either worker or supervisor.
  • restart: Often transient for dynamic workers, meaning they only restart if they crash unexpectedly, not if they exit normally.
  • shutdown: Timeout for graceful shutdown.

Code: Create Dynamic Workers

This example shows a supervisor starting two unique 'task' processes dynamically. Each task maintains its own count.

Run it to see how new processes are spawned and how you can interact with them individually.

-module(dynamic_start_example).
-behaviour(supervisor).

-export([start_link/0, init/1, start_task/1, call_task/2, run/0]).
-export([task_init/1, task_handle_call/3, task_terminate/2]).

% --- Supervisor part ---
start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
    Strategy = {simple_one_for_one, 0, 1},
    Children = [],
    {ok, {Strategy, Children}}.

start_task(TaskId) ->
    io:format("Supervisor: Starting task ~p~n", [TaskId]),
    ChildSpec = #{
        id => TaskId,
        start => {gen_server, start_link, [{local, TaskId}, ?MODULE, [], []]},
        type => worker,
        restart => transient,
        shutdown => 5000
    },
    supervisor:start_child(?MODULE, ChildSpec).

call_task(TaskId, Message) ->
    gen_server:call(TaskId, Message).

% --- Worker part (this module acts as a gen_server for the tasks) ---
task_init([]) ->
    io:format("Task ~p: Initializing with count 0~n", [self()]),
    {ok, 0}. % Initial state for the task

task_handle_call(get_count, _From, State) ->
    io:format("Task ~p: Getting count ~p~n", [self(), State]),
    {reply, State, State}.
task_handle_call({increment, Value}, _From, State) ->
    NewState = State + Value,
    io:format("Task ~p: Incrementing by ~p to ~p~n", [self(), Value, NewState]),
    {reply, NewState, NewState}.

task_terminate(_Reason, State) ->
    io:format("Task ~p: Terminating with final state ~p~n", [self(), State]),
    ok.

% --- Entry point for runnable example ---
run() ->
    io:format("~n--- Starting Dynamic Task Example ---~n"),
    {ok, SupPid} = dynamic_start_example:start_link(),
    io:format("Supervisor started: ~p~n", [SupPid]),

    io:format("~nStarting Task 'task_alpha':~n"),
    dynamic_start_example:start_task(task_alpha),
    timer:sleep(100), % Give it a moment to start

    Count1 = dynamic_start_example:call_task(task_alpha, get_count),
    io:format("Task 'task_alpha' count: ~p~n", [Count1]),

    dynamic_start_example:call_task(task_alpha, {increment, 7}),
    Count2 = dynamic_start_example:call_task(task_alpha, get_count),
    io:format("Task 'task_alpha' count after increment: ~p~n", [Count2]),

    io:format("~nStarting Task 'task_beta':~n"),
    dynamic_start_example:start_task(task_beta),
    timer:sleep(100),

    Count3 = dynamic_start_example:call_task(task_beta, get_count),
    io:format("Task 'task_beta' count: ~p~n", [Count3]),

    dynamic_start_example:call_task(task_beta, {increment, 12}),
    Count4 = dynamic_start_example:call_task(task_beta, get_count),
    io:format("Task 'task_beta' count after increment: ~p~n", [Count4]),

    % In a real app, you'd stop the supervisor or individual tasks here.
    % For this example, we'll let them run.
    io:format("--- Dynamic Task Start Demo Finished ---~n"),
    ok.

Terminating Dynamic Children

Just as you can start processes dynamically, you can also stop them. The supervisor:terminate_child/2 function is used for this.

  • It takes the SupRef and the ChildId (the id from the child specification) as arguments.
  • The supervisor will send an exit signal to the child, initiating a graceful shutdown.
  • Once terminated, the child is removed from the supervisor's list, freeing up resources.

This is crucial for managing resources and ensuring processes don't linger unnecessarily.

Code: Terminate Dynamic Workers

This example demonstrates starting a task, interacting with it, and then gracefully stopping it using terminate_child/2. Notice the output when the task terminates.

-module(dynamic_stop_example).
-behaviour(supervisor).

-export([start_link/0, init/1, start_task/1, call_task/2, stop_task/1, run/0]).
-export([task_init/1, task_handle_call/3, task_terminate/2]).

% --- Supervisor part ---
start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
    Strategy = {simple_one_for_one, 0, 1},
    Children = [],
    {ok, {Strategy, Children}}.

start_task(TaskId) ->
    io:format("Supervisor: Starting task ~p~n", [TaskId]),
    ChildSpec = #{
        id => TaskId,
        start => {gen_server, start_link, [{local, TaskId}, ?MODULE, [], []]},
        type => worker,
        restart => transient,
        shutdown => 5000
    },
    supervisor:start_child(?MODULE, ChildSpec).

call_task(TaskId, Message) ->
    gen_server:call(TaskId, Message).

stop_task(TaskId) ->
    io:format("Supervisor: Stopping task ~p~n", [TaskId]),
    supervisor:terminate_child(?MODULE, TaskId).

% --- Worker part (this module acts as a gen_server for the tasks) ---
task_init([]) ->
    io:format("Task ~p: Initializing with count 0~n", [self()]),
    {ok, 0}.

task_handle_call(get_count, _From, State) ->
    io:format("Task ~p: Getting count ~p~n", [self(), State]),
    {reply, State, State}.
task_handle_call({increment, Value}, _From, State) ->
    NewState = State + Value,
    io:format("Task ~p: Incrementing by ~p to ~p~n", [self(), Value, NewState]),
    {reply, NewState, NewState}.

task_terminate(_Reason, State) ->
    io:format("Task ~p: Terminating with final state ~p~n", [self(), State]),
    ok.

% --- Entry point for runnable example ---
run() ->
    io:format("~n--- Terminating Dynamic Task Example ---~n"),
    {ok, SupPid} = dynamic_stop_example:start_link(),
    io:format("Supervisor started: ~p~n", [SupPid]),

    io:format("~nStarting Task 'temp_task':~n"),
    dynamic_stop_example:start_task(temp_task),
    timer:sleep(100),

    dynamic_stop_example:call_task(temp_task, {increment, 100}),
    Count = dynamic_stop_example:call_task(temp_task, get_count),
    io:format("Task 'temp_task' current count: ~p~n", [Count]),

    io:format("~nStopping Task 'temp_task':~n"),
    dynamic_stop_example:stop_task(temp_task),
    timer:sleep(100), % Give it a moment to terminate

    io:format("~nAttempting to call 'temp_task' after termination (will fail):~n"),
    CatchResult = try dynamic_stop_example:call_task(temp_task, get_count) of
                      Result -> Result
                  catch
                      error:Reason -> {error, Reason}
                  end,
    io:format("Call result after stop: ~p~n", [CatchResult]),

    supervisor:stop(SupPid), % Clean up the supervisor
    io:format("Supervisor stopped.~n"),
    io:format("--- Dynamic Task Stop Demo Finished ---~n"),
    ok.

Practical Use Cases

Dynamic process management is a powerful tool in Erlang. Here are some common scenarios where it shines:

  • Web Servers: Spawning a new process for each incoming client connection.
  • Connection Pools: Managing a pool of database connections, creating new ones as needed.
  • Batch Processors: Starting worker processes to handle items from a queue.
  • User Sessions: Managing individual user sessions in a multi-user application.

It allows your system to adapt to varying loads and efficiently manage transient resources.

Quick Check

You've learned about starting and stopping dynamic child processes. Let's test your understanding.

Recap: Dynamic Processes

We've explored dynamic process management, a key technique for building adaptable Erlang systems:

  • Dynamic processes are created and destroyed on demand, saving resources.
  • The simple_one_for_one strategy is typically used by supervisors managing dynamic children.
  • supervisor:start_child/2 is used to add new processes, providing a unique child specification for each.
  • supervisor:terminate_child/2 ensures graceful shutdown and removal of dynamic processes.

Mastering this allows your applications to efficiently scale and respond to changing demands.

자주 묻는 질문

“동적 프로세스 관리” 강의는 무료인가요?

네 — “동적 프로세스 관리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의 전체를 잠금 해제할 수 있습니다. Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의에는 총 4개의 강의가 포함되어 있습니다.

“동적 프로세스 관리”에서 뭘 배우나요?

감독자 내에서 자식 프로세스를 동적으로 시작하고 중지하는 방법을 숙달하여 적응력 있고 자원을 효율적으로 사용하는 시스템을 구축합니다. 브라우저에서 직접 실행하는 실습 코드로 Erlang OTP: Distributed & Fault-Tolerant Systems Programming을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Erlang OTP: Distributed & Fault-Tolerant Systems Programming을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Erlang OTP: Distributed & Fault-Tolerant Systems Programming은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“동적 프로세스 관리” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Erlang OTP: Distributed & Fault-Tolerant Systems Programming 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 복잡한 감독 트리
  2. 동적 프로세스 관리
  3. 고급 재시작 전략
  4. 감독자 브리지와 혼합 프로세스 계층 구조
← Erlang OTP: Distributed & Fault-Tolerant Systems Programming(으)로 돌아가기