Elixir 1.7

Agent




elixir

Agent

एजेंट राज्य के चारों ओर एक साधारण अमूर्त हैं।

अक्सर अमृत में राज्य को साझा करने या संग्रहीत करने की आवश्यकता होती है जिसे अलग-अलग प्रक्रियाओं से या एक ही प्रक्रिया द्वारा समय पर अलग-अलग बिंदुओं से एक्सेस किया जाना चाहिए।

Agent मॉड्यूल एक मूल सर्वर कार्यान्वयन प्रदान करता है जो राज्य को एक साधारण एपीआई के माध्यम से पुनर्प्राप्त और अद्यतन करने की अनुमति देता है।

उदाहरण

उदाहरण के लिए, मिक्स टूल में जो अमृत के साथ जहाज करता है, हमें किसी दिए गए प्रोजेक्ट द्वारा निष्पादित सभी कार्यों का एक सेट रखने की आवश्यकता है। चूंकि यह सेट साझा किया गया है, हम इसे एक एजेंट के साथ लागू कर सकते हैं:

defmodule Mix.TasksServer do
  use Agent

  def start_link(_) do
    Agent.start_link(fn -> MapSet.new end, name: __MODULE__)
  end

  @doc "Checks if the task has already executed"
  def executed?(task, project) do
    item = {task, project}
    Agent.get(__MODULE__, fn set ->
      item in set
    end)
  end

  @doc "Marks a task as executed"
  def put_task(task, project) do
    item = {task, project}
    Agent.update(__MODULE__, &MapSet.put(&1, item))
  end

  @doc "Resets the executed tasks and returns the previous list of tasks"
  def take_all() do
    Agent.get_and_update(__MODULE__, fn set ->
      {Enum.into(set, []), MapSet.new}
    end)
  end
end

एजेंट क्लाइंट और सर्वर API (GenServers के समान) के बीच एक अलगाव प्रदान करते हैं। विशेष रूप से, Agent को दिए गए अनाम फ़ंक्शन एजेंट (सर्वर) के अंदर निष्पादित होते हैं। यह अंतर महत्वपूर्ण है क्योंकि आप एजेंट के अंदर महंगे संचालन से बचना चाह सकते हैं, क्योंकि वे अनुरोध को पूरा होने तक एजेंट को प्रभावी रूप से रोक देंगे।

इन दो उदाहरणों पर विचार करें:

# Compute in the agent/server
def get_something(agent) do
  Agent.get(agent, fn state -> do_something_expensive(state) end)
end

# Compute in the agent/client
def get_something(agent) do
  Agent.get(agent, &(&1)) |> do_something_expensive()
end

पहला फ़ंक्शन एजेंट को ब्लॉक करता है। दूसरा फ़ंक्शन क्लाइंट के लिए सभी स्थिति की प्रतिलिपि बनाता है और फिर क्लाइंट में ऑपरेशन निष्पादित करता है। विचार करने के लिए एक पहलू यह है कि क्या डेटा सर्वर में प्रसंस्करण की आवश्यकता के लिए पर्याप्त बड़ा है, कम से कम शुरुआत में, या क्लाइंट को भेजे जाने के लिए पर्याप्त रूप से छोटा है। एक अन्य कारक यह है कि क्या डेटा को परमाणु रूप से संसाधित करने की आवश्यकता है: एजेंट के बाहर राज्य और कॉलिंग do_something_expensive(state) का मतलब है कि एजेंट की स्थिति को इस बीच अपडेट किया जा सकता है। अद्यतनों के मामले में यह विशेष रूप से महत्वपूर्ण है क्योंकि सर्वर के बजाय क्लाइंट में नए राज्य की गणना करने से दौड़ की स्थिति पैदा हो सकती है यदि कई क्लाइंट एक ही राज्य को अलग-अलग मानों में अपडेट करने का प्रयास कर रहे हैं।

अंत में नोट use Agent child_spec/1 फ़ंक्शन को परिभाषित करता है, जिससे परिभाषित मॉड्यूल को पर्यवेक्षण के पेड़ के नीचे रखा जा सकता है। उत्पन्न child_spec/1 को निम्नलिखित विकल्पों के साथ अनुकूलित किया जा सकता है:

  • :id - बाल विनिर्देश पहचानकर्ता, वर्तमान मॉड्यूल में चूक
  • :start - बच्चे की प्रक्रिया कैसे शुरू करें ( __MODULE__.start_link/1 को कॉल करने के लिए चूक __MODULE__.start_link/1 )
  • :restart - जब बच्चे को फिर से शुरू किया जाना चाहिए, चूक करना :permanent
  • :shutdown - बच्चे को कैसे बंद किया जाए

उदाहरण के लिए:

use Agent, restart: :transient, shutdown: 10_000

अधिक जानकारी के लिए Supervisor डॉक्स देखें।

नाम पंजीकरण

एक एजेंट जनरल नाम के नियमों के समान ही है। GenServer प्रलेखन में इसके बारे में और पढ़ें।

वितरित एजेंटों पर एक शब्द

वितरित एजेंटों की सीमाओं पर विचार करना महत्वपूर्ण है। एजेंट दो एपीआई प्रदान करते हैं, एक जो गुमनाम कार्यों के साथ काम करता है और दूसरा जो एक स्पष्ट मॉड्यूल, फ़ंक्शन और तर्कों की अपेक्षा करता है।

एकाधिक नोड्स के साथ एक वितरित सेटअप में, एपीआई जो अनाम कार्यों को स्वीकार करता है केवल तभी काम करता है जब कॉलर (क्लाइंट) और एजेंट के पास कॉलर मॉड्यूल का एक ही संस्करण हो।

ध्यान रखें कि एजेंटों के साथ "रोलिंग अपग्रेड" करते समय यह समस्या भी दिखाई देती है। रोलिंग अपग्रेड से हमारा मतलब निम्न स्थिति से है: आप अपने कुछ नोड्स को बंद करके अपने सॉफ़्टवेयर के नए संस्करण को तैनात करना चाहते हैं और उन्हें सॉफ़्टवेयर के नए संस्करण को चलाने वाले नोड्स के साथ प्रतिस्थापित करना चाहते हैं। इस सेटअप में, आपके पर्यावरण के हिस्से में दिए गए मॉड्यूल का एक संस्करण होगा और दूसरा भाग उसी मॉड्यूल का दूसरा संस्करण (नया वाला) होगा।

सबसे अच्छा समाधान केवल स्पष्ट मॉड्यूल, फ़ंक्शन और तर्क API का उपयोग करना है जब वितरित एजेंटों के साथ काम करना।

हॉट कोड स्वैपिंग

एक एजेंट के पास अपने कोड हॉट स्वेप्ड लाइव हो सकते हैं बस एक मॉड्यूल, फ़ंक्शन, और तर्क को अद्यतन निर्देश पर टैप करके। उदाहरण के लिए, कल्पना करें कि आपके पास एक एजेंट का नाम है :sample और आप इसकी आंतरिक स्थिति को कीवर्ड सूची से मानचित्र में बदलना चाहते हैं। यह निम्नलिखित निर्देश के साथ किया जा सकता है:

{:update, :sample, {:advanced, {Enum, :into, [%{}]}}}

एजेंट की स्थिति को पहले तर्क के रूप में दी गई दलीलों की सूची ( [%{}] ) में जोड़ा जाएगा।

सारांश

प्रकार

agent()

एजेंट संदर्भ

name()

एजेंट का नाम

on_start()

start* कार्यों का मान लौटाएँ

state()

एजेंट राज्य

कार्य

कास्ट (एजेंट, मज़ा)

एजेंट स्थिति पर एक कास्ट ( आग और भूल ) संचालन करता है

कास्ट (एजेंट, मॉड्यूल, मज़ा, आर्ग्स)

एजेंट स्थिति पर एक कास्ट ( आग और भूल ) संचालन करता है

child_spec/1

एक पर्यवेक्षक के तहत एक एजेंट शुरू करने के लिए एक विनिर्देश देता है

प्राप्त करें (एजेंट, मज़ा, टाइमआउट \\ 5000)

दिए गए अनाम फ़ंक्शन के माध्यम से एजेंट मान प्राप्त करता है

प्राप्त करें (एजेंट, मॉड्यूल, मज़ा, आर्ग्स, टाइमआउट \\ 5000)

दिए गए फ़ंक्शन के माध्यम से एक एजेंट मूल्य प्राप्त करता है

get_and_update (एजेंट, मौज, टाइमआउट \\ 5000)

हो जाता है और दिए गए अनाम फ़ंक्शन के माध्यम से एक ऑपरेशन में एजेंट स्थिति को अपडेट करता है

get_and_update (एजेंट, मॉड्यूल, मस्ती, आर्ग्स, टाइमआउट \\ 5000)

हो जाता है और दिए गए फ़ंक्शन के माध्यम से एक ऑपरेशन में एजेंट स्थिति को अपडेट करता है

प्रारंभ (मज़ा, विकल्प \\ [])

लिंक के बिना एक एजेंट प्रक्रिया शुरू करता है (पर्यवेक्षण के पेड़ के बाहर)

प्रारंभ (मॉड्यूल, मज़ा, आर्ग, विकल्प \\ [])

दिए गए मॉड्यूल, फ़ंक्शन और तर्कों के लिंक के बिना एक एजेंट शुरू करता है

start_link (मज़ा, विकल्प \\ [])

दिए गए फ़ंक्शन के साथ वर्तमान प्रक्रिया से जुड़ा एक एजेंट शुरू करता है

start_link (मॉड्यूल, मज़ा, आर्ग, विकल्प \\ [])

वर्तमान प्रक्रिया से जुड़ा एक एजेंट शुरू करता है

बंद करो (एजेंट, कारण \\: सामान्य, मध्यांतर \\: अनंत)

दिए गए reason साथ एजेंट को समकालिक रूप से रोकता है

अद्यतन (एजेंट, मज़ा, टाइमआउट \\ 5000)

दिए गए अनाम फ़ंक्शन के माध्यम से एजेंट स्थिति को अद्यतन करता है

अपडेट (एजेंट, मॉड्यूल, मज़ा, आर्ग्स, टाइमआउट \\ 5000)

दिए गए फ़ंक्शन के माध्यम से एजेंट स्थिति को अपडेट करता है

प्रकार

एजेंट ()

agent() :: pid() | {atom(), node()} | name()

एजेंट संदर्भ

नाम ()

name() :: atom() | {:global, term()} | {:via, module(), term()}

एजेंट का नाम

on_start ()

on_start() :: {:ok, pid()} | {:error, {:already_started, pid()} | term()}

start* कार्यों का मान लौटाएँ

राज्य ()

state() :: term()

एजेंट राज्य

कार्य

कास्ट (एजेंट, मज़ा)

cast(agent(), (state() -> state())) :: :ok

एजेंट स्थिति पर एक कास्ट ( आग और भूल ) संचालन करता है।

फ़ंक्शन fun उस agent को भेजा जाता है जो एजेंट राज्य को पारित करने वाले फ़ंक्शन को आमंत्रित करता है। fun का वापसी मूल्य एजेंट की नई स्थिति बन जाता है।

ध्यान दें कि cast रिटर्न :ok है, चाहे agent (या नोड को इस पर रहना चाहिए) मौजूद है।

कास्ट (एजेंट, मॉड्यूल, मज़ा, आर्ग्स)

cast(agent(), module(), atom(), [term()]) :: :ok

एजेंट स्थिति पर एक कास्ट ( आग और भूल ) संचालन करता है।

एक cast/2 रूप में ही लेकिन एक मॉड्यूल, फ़ंक्शन और तर्कों को एक अनाम फ़ंक्शन के बजाय अपेक्षित है। दी गई दलीलों की सूची में पहले तर्क के रूप में राज्य जोड़ा जाता है।

child_spec (arg) (1.5.0 से)

एक पर्यवेक्षक के तहत एक एजेंट शुरू करने के लिए एक विनिर्देश देता है।

Supervisor देखें।

प्राप्त करें (एजेंट, मज़ा, टाइमआउट \\ 5000)

get(agent(), (state() -> a), timeout()) :: a when a: var

दिए गए अनाम फ़ंक्शन के माध्यम से एजेंट मान प्राप्त करता है।

फ़ंक्शन fun उस agent को भेजा जाता है जो एजेंट राज्य को पारित करने वाले फ़ंक्शन को आमंत्रित करता है। फ़ंक्शन आमंत्रण का परिणाम इस फ़ंक्शन से लौटाया जाता है।

timeout शून्य से अधिक पूर्णांक है जो निर्दिष्ट करता है कि फ़ंक्शन निष्पादित करने से पहले कितने मिलीसेकंड की अनुमति है और परिणाम मान लौटाता है, या परमाणु :infinity अनिश्चित काल तक प्रतीक्षा करने के लिए। यदि निर्दिष्ट समय के भीतर कोई परिणाम प्राप्त नहीं होता है, तो फ़ंक्शन कॉल विफल हो जाता है और कॉलर बाहर निकल जाता है।

उदाहरण

iex> {:ok, pid} = Agent.start_link(fn -> 42 end)
iex> Agent.get(pid, fn state -> state end)
42

प्राप्त करें (एजेंट, मॉड्यूल, मज़ा, आर्ग्स, टाइमआउट \\ 5000)

get(agent(), module(), atom(), [term()], timeout()) :: any()

दिए गए फ़ंक्शन के माध्यम से एक एजेंट मूल्य प्राप्त करता है।

जैसे ही get/3 लेकिन एक गुमनाम फ़ंक्शन के बजाय एक मॉड्यूल, फ़ंक्शन, और तर्क की अपेक्षा की जाती है। दी गई दलीलों की सूची में पहले तर्क के रूप में राज्य जोड़ा जाता है।

get_and_update (एजेंट, मौज, टाइमआउट \\ 5000)

get_and_update(agent(), (state() -> {a, state()}), timeout()) :: a when a: var

हो जाता है और दिए गए अनाम फ़ंक्शन के माध्यम से एक ऑपरेशन में एजेंट स्थिति को अपडेट करता है।

फ़ंक्शन fun उस agent को भेजा जाता है जो एजेंट राज्य को पारित करने वाले फ़ंक्शन को आमंत्रित करता है। फ़ंक्शन को दो तत्वों के साथ एक टपल लौटना चाहिए, पहला लौटाया जाने वाला मान (यानी, "प्राप्त" मान) और दूसरा एजेंट का नया राज्य है।

timeout शून्य से अधिक पूर्णांक है जो निर्दिष्ट करता है कि फ़ंक्शन निष्पादित करने से पहले कितने मिलीसेकंड की अनुमति है और परिणाम मान लौटाता है, या परमाणु :infinity अनिश्चित काल तक प्रतीक्षा करने के लिए। यदि निर्दिष्ट समय के भीतर कोई परिणाम प्राप्त नहीं होता है, तो फ़ंक्शन कॉल विफल हो जाता है और कॉलर बाहर निकल जाता है।

उदाहरण

iex> {:ok, pid} = Agent.start_link(fn -> 42 end)
iex> Agent.get_and_update(pid, fn state -> {state, state + 1} end)
42
iex> Agent.get(pid, fn state -> state end)
43

get_and_update (एजेंट, मॉड्यूल, मस्ती, आर्ग्स, टाइमआउट \\ 5000)

get_and_update(agent(), module(), atom(), [term()], timeout()) :: any()

हो जाता है और दिए गए फ़ंक्शन के माध्यम से एक ऑपरेशन में एजेंट स्थिति को अपडेट करता है।

एक अनाम फ़ंक्शन के बजाय get_and_update/3 लेकिन एक मॉड्यूल, फ़ंक्शन और तर्कों के रूप में समान है। दी गई दलीलों की सूची में पहले तर्क के रूप में राज्य जोड़ा जाता है।

प्रारंभ (मज़ा, विकल्प \\ [])

start((() -> term()), GenServer.options()) :: on_start()

लिंक के बिना एक एजेंट प्रक्रिया शुरू करता है (एक पर्यवेक्षण के पेड़ के बाहर)।

अधिक जानकारी के लिए start_link/2 देखें।

उदाहरण

iex> {:ok, pid} = Agent.start(fn -> 42 end)
iex> Agent.get(pid, fn state -> state end)
42

प्रारंभ (मॉड्यूल, मज़ा, आर्ग, विकल्प \\ [])

start(module(), atom(), [any()], GenServer.options()) :: on_start()

दिए गए मॉड्यूल, फ़ंक्शन और तर्कों के लिंक के बिना एक एजेंट शुरू करता है।

अधिक जानकारी के लिए start_link/4 देखें।

start_link (मज़ा, विकल्प \\ [])

start_link((() -> term()), GenServer.options()) :: on_start()

दिए गए फ़ंक्शन के साथ वर्तमान प्रक्रिया से जुड़ा एक एजेंट शुरू करता है।

इसका उपयोग अक्सर एजेंट को पर्यवेक्षण पेड़ के हिस्से के रूप में शुरू करने के लिए किया जाता है।

एक बार एजेंट के आने के बाद, दिए गए फंक्शन fun को लागू किया जाता है और इसका रिटर्न वैल्यू एजेंट स्टेट के रूप में उपयोग किया जाता है। ध्यान दें कि start_link/2 तब तक वापस नहीं आता जब तक कि दिए गए फ़ंक्शन वापस नहीं आए।

विकल्प

:name विकल्प को पंजीकरण के लिए उपयोग किया जाता है जैसा कि मॉड्यूल प्रलेखन में वर्णित है।

यदि :timeout विकल्प मौजूद है, तो एजेंट को आरंभ में मिलीसेकेंड की अधिकांश दी गई संख्या पर खर्च करने की अनुमति दी जाती है या इसे समाप्त कर दिया जाएगा और प्रारंभ फ़ंक्शन {:error, :timeout} वापस आ जाएगा।

यदि :debug विकल्प मौजूद है, तो :sys मॉड्यूल में संबंधित फ़ंक्शन को लागू किया जाएगा।

यदि :spawn_opt विकल्प मौजूद है, तो इसका मूल्य प्रक्रिया के रूप में अंतर्निहित प्रक्रिया के विकल्प के रूप में पारित किया जाएगा :spawn_opt Process.spawn/4

मान लौटाएं

यदि सर्वर सफलतापूर्वक बनाया और आरंभ किया गया है, तो फ़ंक्शन {:ok, pid} , जहां pid सर्वर का PID है, लौटता है। यदि निर्दिष्ट नाम वाला कोई एजेंट पहले से मौजूद है, तो फ़ंक्शन उस प्रक्रिया की पीआईडी ​​के साथ {:error, {:already_started, pid}} है।

यदि दी गई फ़ंक्शन कॉलबैक विफल हो जाती है, तो फ़ंक्शन {:error, reason} लौटता है।

उदाहरण

iex> {:ok, pid} = Agent.start_link(fn -> 42 end)
iex> Agent.get(pid, fn state -> state end)
42

iex> {:error, {exception, _stacktrace}} = Agent.start(fn -> raise "oops" end)
iex> exception
%RuntimeError{message: "oops"}

start_link (मॉड्यूल, मज़ा, आर्ग, विकल्प \\ [])

start_link(module(), atom(), [any()], GenServer.options()) :: on_start()

वर्तमान प्रक्रिया से जुड़ा एक एजेंट शुरू करता है।

एक अनाम फ़ंक्शन के बजाय start_link/2 लेकिन एक मॉड्यूल, फ़ंक्शन और तर्क के रूप में समान होने की उम्मीद है; module में fun राज्य को आरंभ करने के लिए दिए गए तर्कों के साथ कहा जाएगा।

बंद करो (एजेंट, कारण \\: सामान्य, मध्यांतर \\: अनंत)

stop(agent(), reason :: term(), timeout()) :: :ok

दिए गए reason साथ एजेंट को समकालिक रूप से रोकता है।

यह रिटर्न :ok अगर एजेंट दिए गए कारण के साथ समाप्त होता है। यदि एजेंट किसी अन्य कारण से समाप्त होता है, तो कॉल बाहर निकल जाएगी।

यह फ़ंक्शन त्रुटि रिपोर्टिंग के बारे में ओटीपी शब्दार्थ रखता है। यदि कारण इसके अलावा है :normal :shutdown या {:shutdown, _} , एक त्रुटि रिपोर्ट लॉग की जाएगी।

उदाहरण

iex> {:ok, pid} = Agent.start_link(fn -> 42 end)
iex> Agent.stop(pid)
:ok

अद्यतन (एजेंट, मज़ा, टाइमआउट \\ 5000)

update(agent(), (state() -> state()), timeout()) :: :ok

दिए गए अनाम फ़ंक्शन के माध्यम से एजेंट स्थिति को अद्यतन करता है।

फ़ंक्शन fun उस agent को भेजा जाता है जो एजेंट राज्य को पारित करने वाले फ़ंक्शन को आमंत्रित करता है। fun का वापसी मूल्य एजेंट की नई स्थिति बन जाता है।

यह फ़ंक्शन हमेशा लौटता है :ok

timeout शून्य से अधिक पूर्णांक है जो निर्दिष्ट करता है कि फ़ंक्शन निष्पादित करने से पहले कितने मिलीसेकंड की अनुमति है और परिणाम मान लौटाता है, या परमाणु :infinity अनिश्चित काल तक प्रतीक्षा करने के लिए। यदि निर्दिष्ट समय के भीतर कोई परिणाम प्राप्त नहीं होता है, तो फ़ंक्शन कॉल विफल हो जाता है और कॉलर बाहर निकल जाता है।

उदाहरण

iex> {:ok, pid} = Agent.start_link(fn -> 42 end)
iex> Agent.update(pid, fn state -> state + 1 end)
:ok
iex> Agent.get(pid, fn state -> state end)
43

अपडेट (एजेंट, मॉड्यूल, मज़ा, आर्ग्स, टाइमआउट \\ 5000)

update(agent(), module(), atom(), [term()], timeout()) :: :ok

दिए गए फ़ंक्शन के माध्यम से एजेंट स्थिति को अपडेट करता है।

update/3 रूप में एक ही है लेकिन एक मॉड्यूल, फ़ंक्शन, और तर्क एक अनाम फ़ंक्शन के बजाय अपेक्षित हैं। दी गई दलीलों की सूची में पहले तर्क के रूप में राज्य जोड़ा जाता है।