You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Actor模型如何解决共享状态问题?求Erlang/Elixir取款示例

Actor模型下Erlang/Elixir规避共享状态的取款实现

Actor模型规避共享状态的核心逻辑是:让单个进程作为状态的唯一持有者,所有存取款操作都以消息形式与该进程交互,状态仅在进程内部更新,绝不对外暴露可被多进程直接访问的共享存储(比如ETS)。以下是具体实现示例:


Erlang 实现示例

-module(bank_account).
-export([start/1, withdraw/2, deposit/2, get_balance/1]).

% 启动账户进程,初始化余额
start(InitialBalance) ->
    spawn(fun() -> account_loop(InitialBalance) end).

% 发送取款请求并等待结果
withdraw(AccountPid, Amount) ->
    AccountPid ! {withdraw, self(), Amount},
    receive
        {result, Result} -> Result
    end.

% 发送存款请求并等待结果
deposit(AccountPid, Amount) ->
    AccountPid ! {deposit, self(), Amount},
    receive
        {result, Result} -> Result
    end.

% 查询当前余额
get_balance(AccountPid) ->
    AccountPid ! {get_balance, self()},
    receive
        {balance, Balance} -> Balance
    end.

% 进程内部循环,维护余额状态(仅该进程能修改)
account_loop(Balance) ->
    receive
        {withdraw, From, Amount} when Amount > 0, Balance >= Amount ->
            NewBalance = Balance - Amount,
            From ! {result, {ok, NewBalance}},
            account_loop(NewBalance);
        {withdraw, From, _Amount} ->
            From ! {result, {error, insufficient_funds}},
            account_loop(Balance);
        {deposit, From, Amount} when Amount > 0 ->
            NewBalance = Balance + Amount,
            From ! {result, {ok, NewBalance}},
            account_loop(NewBalance);
        {deposit, From, _Amount} ->
            From ! {result, {error, invalid_amount}},
            account_loop(Balance);
        {get_balance, From} ->
            From ! {balance, Balance},
            account_loop(Balance)
    end.

关键说明

  • 余额Balance仅存在于account_loop/1的进程栈中,没有任何全局共享存储,只有该进程能修改状态。
  • 所有外部操作都通过消息传递完成,进程处理请求后回复结果,状态更新后进入下一次循环,天然保证操作的原子性,不会出现多进程竞争问题。

Elixir 实现示例

基于Erlang VM,逻辑一致,语法更贴近函数式风格:

defmodule BankAccount do
  def start(initial_balance) do
    spawn(fn -> loop(initial_balance) end)
  end

  def withdraw(account_pid, amount) do
    send(account_pid, {:withdraw, self(), amount})
    receive do
      {:result, result} -> result
    end
  end

  def deposit(account_pid, amount) do
    send(account_pid, {:deposit, self(), amount})
    receive do
      {:result, result} -> result
    end
  end

  def get_balance(account_pid) do
    send(account_pid, {:get_balance, self()})
    receive do
      {:balance, balance} -> balance
    end
  end

  defp loop(balance) do
    receive do
      {:withdraw, from, amount} when amount > 0 and balance >= amount ->
        new_balance = balance - amount
        send(from, {:result, {:ok, new_balance}})
        loop(new_balance)
      {:withdraw, from, _amount} ->
        send(from, {:result, {:error, :insufficient_funds}})
        loop(balance)
      {:deposit, from, amount} when amount > 0 ->
        new_balance = balance + amount
        send(from, {:result, {:ok, new_balance}})
        loop(new_balance)
      {:deposit, from, _amount} ->
        send(from, {:result, {:error, :invalid_amount}})
        loop(balance)
      {:get_balance, from} ->
        send(from, {:balance, balance})
        loop(balance)
    end
  end
end

补充说明

你提到的「将余额编码到消息中传递」存在逻辑误区:如果让多个进程持有余额副本,反而会引发状态不一致问题。Actor模型规避共享状态的正确方式是让单个进程垄断状态所有权,所有操作都通过与该进程通信完成,从根源上避免了共享状态的竞争。

内容的提问来源于stack exchange,提问作者wang kai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:05:21