zoukankan      html  css  js  c++  java
  • elixir 高可用系列(一) Agent

    概述

    elixir 本身是一种 immutable 的语言,默认情况下,进程间是不共享任何状态的,进程之间通过消息来交互。
    而 Agent 则封装了一种进程间共享状态的方式,通过这种方式,不用显式的写 send/receieve 的代码,就能方便的在进程之间共享状态。

    使用方法

    不用 Agent 来管理状态

    首先,看一个在不用 Agent 的情况下,如何获取进程状态的例子。

    defmodule WithoutAgent do
      def start do
        Map.new()
      end
    
      def get(map, key) do
        if Map.has_key?(map, key) do
          Map.get(map, key)
        else
          nil
        end
      end
    
      def put(map, key, val) do
        Map.put(map, key, val)
      end
    
      def delete(map, key) do
        Map.delete(map, key)
      end
    end
    

    测试 WithoutAgent 的使用:

    iex> m = WithoutAgent.start
    %{}
    iex> WithoutAgent.get(m, "map-key")
    nil
    
    iex> m = WithoutAgent.put(m, "map-key", "map-val")
    %{"map-key" => "map-val"}
    iex> WithoutAgent.get(m, "map-key")
    "map-val"
    
    iex> m = WithoutAgent.delete(m, "map-key")
    %{}
    iex> m = WithoutAgent.get(m, "map-key")
    nil
    

    从上面的使用可以看出,为了使用 WithoutAgent 中的状态(一个 map),外部还必须要自己管理 WithoutAgent 的返回的状态 m,
    通过 WithoutAgent 来改变状态时,每次都要将当前状态 m 作为一个参数传给 WithoutAgent。

    只有一个进程使用 WithoutAgent 时,上述方式没有什么问题,当有多个进程使用 WithoutAgent,每个进程持有的状态 m 很难保持一致。

    使用 Agent 来管理状态

    elixir 中的 Agent 其实并不是 elixir 发明的新东西,而是封装了 erlang OTP 中现有的 ETS (Erlang Term Storage)
    使用 Agent 来重新实现上面的例子:

    defmodule WithAgent do
      def start do
        Agent.start_link(fn -> Map.new end, name: __MODULE__)
      end
    
      def get(key) do
        Agent.get(__MODULE__, fn map ->
          if Map.has_key?(map, key) do
            Map.get(map, key)
          else
            nil
          end
        end)
      end
    
      def put(key, val) do
        Agent.update(__MODULE__, &Map.put(&1, key, val))
      end
    
      def delete(key) do
        Agent.get_and_update(__MODULE__, fn map ->
          if Map.has_key?(map, key) do
            Map.pop(map, key)
          else
            nil
          end
        end)
      end
    end
    

    测试 WithAgent 的使用:

    iex> WithAgent.start
    {:ok, #PID<0.108.0>}
    iex> WithAgent.get("map-key")
    nil
    
    iex> WithAgent.put("map-key", "map-val")
    :ok
    iex> WithAgent.get("map-key")
    "map-val"
    
    iex> WithAgent.delete("map-key")
    "map-val"
    iex> WithAgent.get("map-key")
    nil
    

    从上面的使用中可以看出,使用了 Agent 之后,使用方完全不用自己管理 WithAgent 的状态,只要操作状态即可。
    这样,多个进程同时使用 WithAgent 时,也不用管状态冲突的事情,状态如果有冲突也是在 WithAgent 中自己管理。

    总结

    总的来说,Agent 就是状态的简单的封装,方便进程间状态的共享。
    此外,除了上面用的方法,Agent 中的所有方法参照:Agent

    来源:http://blog.iotalabs.io/

  • 相关阅读:
    分享
    慕课网-软件测试基础-学习笔记
    向量内积(点乘)和外积(叉乘)概念及几何意义
    使用opencv3+python实现视频运动目标检测
    解决opencv3运行opencv2代码时报错的修改备忘录
    分享
    OpenCV学习笔记
    LeetCode
    LeetCode
    npm安装包很慢
  • 原文地址:https://www.cnblogs.com/wang_yb/p/5422683.html
Copyright © 2011-2022 走看看